OBP-API/ideas/obp-abac-quick-reference.md
simonredfern efc1868fd4 BREAKING CHANGE: Switch active-rate-limits endpoint to hour-based format
Changed from full timestamp to hour-only format to match implementation.

OLD: /active-rate-limits/2025-12-31T13:34:46Z (YYYY-MM-DDTHH:MM:SSZ)
NEW: /active-rate-limits/2025-12-31-13 (YYYY-MM-DD-HH)

Benefits:
- API now matches actual implementation (hour-level caching)
- Eliminates timezone/minute truncation confusion
- Clearer semantics: 'active during this hour' not 'at this second'
- Direct cache key mapping improves performance
- Simpler date parsing (no timezone handling needed)

Files changed:
- APIMethods600.scala: Updated endpoint and date parsing
- RateLimitsTest.scala: Updated all test cases to new format
- Glossary.scala: Updated API documentation
- introductory_system_documentation.md: Updated user docs

This is a breaking change but necessary to align API with implementation.
Rate limits are cached and queried at hour granularity, so the API
should reflect that reality.
2025-12-30 17:35:38 +01:00

9.9 KiB

OBP API ABAC Rules - Quick Reference Guide

Most Common Patterns

Quick reference for the most frequently used ABAC rule patterns in OBP API v6.0.0.


1. Self-Access Checks

Allow users to access their own data:

// Basic self-access
userOpt.exists(_.userId == authenticatedUser.userId)

// Self-access by email
userOpt.exists(_.emailAddress == authenticatedUser.emailAddress)

// Self-access for accounts
accountOpt.exists(_.accountHolders.exists(_.userId == authenticatedUser.userId))

2. Role-Based Access

Check user roles and permissions:

// Admin access
authenticatedUserAttributes.exists(attr => attr.name == "role" && attr.value == "admin")

// Multiple role check
authenticatedUserAttributes.exists(attr => attr.name == "role" && List("admin", "manager", "supervisor").contains(attr.value))

// Department-based access
authenticatedUserAttributes.exists(ua => ua.name == "department" && accountAttributes.exists(aa => aa.name == "department" && ua.value == aa.value))

3. Balance and Amount Checks

Transaction and balance validations:

// Transaction within account balance
transactionOpt.exists(t => accountOpt.exists(a => t.amount < a.balance))

// Transaction within 50% of balance
transactionOpt.exists(t => accountOpt.exists(a => t.amount <= a.balance * 0.5))

// Account balance threshold
accountOpt.exists(_.balance > 1000)

// No overdraft
transactionOpt.exists(t => accountOpt.exists(a => a.balance - t.amount >= 0))

4. Currency Matching

Ensure currency consistency:

// Transaction currency matches account
transactionOpt.exists(t => accountOpt.exists(a => t.currency == a.currency))

// Specific currency check
accountOpt.exists(acc => acc.currency == "USD" && acc.balance > 5000)

5. Bank and Account Validation

Verify bank and account relationships:

// Specific bank
bankOpt.exists(_.bankId.value == "gh.29.uk")

// Account belongs to bank
accountOpt.exists(a => bankOpt.exists(b => a.bankId == b.bankId.value))

// Transaction request matches account
transactionRequestOpt.exists(tr => accountOpt.exists(a => tr.this_account_id.value == a.accountId.value))

6. Customer Validation

Customer and KYC checks:

// Customer email matches user
customerOpt.exists(_.email == authenticatedUser.emailAddress)

// Active customer relationship
customerOpt.exists(_.relationshipStatus == "ACTIVE")

// KYC verified
userAttributes.exists(attr => attr.name == "kyc_status" && attr.value == "verified")

// VIP customer
customerAttributes.exists(attr => attr.name == "vip_status" && attr.value == "true")

7. Transaction Type Checks

Validate transaction types:

// Specific transaction type
transactionOpt.exists(_.transactionType.contains("TRANSFER"))

// Amount limit by type
transactionOpt.exists(t => t.amount < 10000 && t.transactionType.exists(_.contains("WIRE")))

// Transaction request type
transactionRequestOpt.exists(_.type == "SEPA")

8. Delegation (On Behalf Of)

Handle delegation scenarios:

// No delegation or self-delegation only
onBehalfOfUserOpt.isEmpty || onBehalfOfUserOpt.exists(_.userId == authenticatedUser.userId)

// Authorized delegation
onBehalfOfUserOpt.isEmpty || onBehalfOfUserAttributes.exists(_.name == "authorized")

// Delegation to target user
onBehalfOfUserOpt.exists(obu => userOpt.exists(u => obu.userId == u.userId))

9. Tier and Level Matching

Check tier compatibility:

// User tier matches account tier
userAttributes.exists(ua => ua.name == "tier" && accountAttributes.exists(aa => aa.name == "tier" && ua.value == aa.value))

// Minimum tier requirement
userAttributes.find(_.name == "tier").exists(_.value.toInt >= 2)

// Premium account
accountAttributes.exists(attr => attr.name == "account_tier" && attr.value == "premium")

10. IP and Context Checks

Request context validation:

// Internal network
callContext.exists(_.ipAddress.exists(_.startsWith("192.168")))

// Specific HTTP method
callContext.exists(_.verb.exists(_ == "GET"))

// URL path check
callContext.exists(_.url.exists(_.contains("/accounts/")))

// Authentication method
authenticatedUserAuthContext.exists(_.key == "auth_method" && _.value == "certificate")

11. Combined Conditions

Complex multi-condition rules:

// Admin OR self-access
authenticatedUserAttributes.exists(_.name == "role" && _.value == "admin") || userOpt.exists(_.userId == authenticatedUser.userId)

// Manager accessing team member's data
authenticatedUserAttributes.exists(_.name == "role" && _.value == "manager") && userOpt.exists(_.userId != authenticatedUser.userId)

// Verified user with proper delegation
userAttributes.exists(_.name == "kyc_status" && _.value == "verified") && (onBehalfOfUserOpt.isEmpty || onBehalfOfUserAttributes.exists(_.name == "authorized"))

12. Safe Option Handling

Always use safe patterns:

// ✅ CORRECT: Use exists()
accountOpt.exists(_.balance > 1000)

// ✅ CORRECT: Use pattern matching
userOpt match { case Some(u) => u.userId == authenticatedUser.userId case None => false }

// ✅ CORRECT: Use forall() for negative conditions
userOpt.forall(!_.isDeleted.getOrElse(false))

// ✅ CORRECT: Use map() with getOrElse()
accountOpt.map(_.balance).getOrElse(0) > 100

// ❌ WRONG: Direct .get (can throw exception)
// accountOpt.get.balance > 1000

13. Real-World Business Scenarios

Loan Approval

customerAttributes.exists(ca => ca.name == "credit_score" && ca.value.toInt > 650) && 
accountOpt.exists(_.balance > 5000) && 
!transactionAttributes.exists(_.name == "fraud_flag")

Wire Transfer Authorization

transactionOpt.exists(t => t.amount < 100000 && t.transactionType.exists(_.contains("WIRE"))) && 
authenticatedUserAttributes.exists(_.name == "wire_authorized" && _.value == "true")

Joint Account Access

accountOpt.exists(a => a.accountHolders.exists(h => 
  h.userId == authenticatedUser.userId || 
  h.emailAddress == authenticatedUser.emailAddress
))

Account Closure (Self-service or Manager)

accountOpt.exists(a => 
  (a.balance == 0 && userOpt.exists(_.userId == authenticatedUser.userId)) || 
  authenticatedUserAttributes.exists(_.name == "role" && _.value == "manager")
)

VIP Priority Processing

customerAttributes.exists(_.name == "vip_status" && _.value == "true") || 
accountAttributes.exists(_.name == "account_tier" && _.value == "platinum") || 
userAttributes.exists(_.name == "priority_level" && _.value.toInt >= 9)

Cross-Border Transaction Compliance

transactionAttributes.exists(_.name == "compliance_docs_attached") && 
transactionOpt.exists(_.amount <= 50000) && 
customerAttributes.exists(_.name == "international_enabled" && _.value == "true")

14. Common Mistakes to Avoid

Wrong Property Names

// WRONG - Snake case
user.user_id
account.account_id
user.email_address

// CORRECT - Camel case
user.userId
account.accountId
user.emailAddress

Wrong Parameter Names

// WRONG - Missing Opt suffix
user.userId
account.balance
bank.bankId

// CORRECT - Proper naming
authenticatedUser.userId  // No Opt (always present)
userOpt.exists(_.userId == ...)  // Has Opt (optional)
accountOpt.exists(_.balance > ...)  // Has Opt (optional)
bankOpt.exists(_.bankId == ...)  // Has Opt (optional)

Unsafe Option Access

// WRONG - Can throw NoSuchElementException
if (accountOpt.isDefined) {
  accountOpt.get.balance > 1000
}

// CORRECT - Safe access
accountOpt.exists(_.balance > 1000)

15. Parameter Reference

Always Available (Required)

  • authenticatedUser - User
  • authenticatedUserAttributes - List[UserAttributeTrait]
  • authenticatedUserAuthContext - List[UserAuthContext]

Optional (Check before use)

  • onBehalfOfUserOpt - Option[User]
  • onBehalfOfUserAttributes - List[UserAttributeTrait]
  • onBehalfOfUserAuthContext - List[UserAuthContext]
  • userOpt - Option[User]
  • userAttributes - List[UserAttributeTrait]
  • bankOpt - Option[Bank]
  • bankAttributes - List[BankAttributeTrait]
  • accountOpt - Option[BankAccount]
  • accountAttributes - List[AccountAttribute]
  • transactionOpt - Option[Transaction]
  • transactionAttributes - List[TransactionAttribute]
  • transactionRequestOpt - Option[TransactionRequest]
  • transactionRequestAttributes - List[TransactionRequestAttributeTrait]
  • customerOpt - Option[Customer]
  • customerAttributes - List[CustomerAttribute]
  • callContext - Option[CallContext]

16. Useful Operators and Methods

Comparison

  • ==, !=, >, <, >=, <=

Logical

  • && (AND), || (OR), ! (NOT)

String Methods

  • contains(), startsWith(), endsWith(), split()

Option Methods

  • isDefined, isEmpty, exists(), forall(), map(), getOrElse()

List Methods

  • exists(), find(), filter(), forall(), map()

Numeric Conversions

  • toInt, toDouble, toLong

Quick Tips

  1. Always use camelCase for property names
  2. Check Optional parameters with exists(), not .get
  3. Use pattern matching for complex Option handling
  4. Attributes are Lists - use collection methods
  5. Rules return Boolean - true = granted, false = denied
  6. Combine conditions with && and ||
  7. Test thoroughly before deploying to production

Getting Full Schema

To get the complete schema with all 170+ examples:

curl -X GET \
  https://your-obp-instance/obp/v6.0.0/management/abac-rules-schema \
  -H 'Authorization: DirectLogin token=YOUR_TOKEN'

  • Full Enhancement Spec: obp-abac-schema-examples-enhancement.md
  • Before/After Comparison: obp-abac-examples-before-after.md
  • Implementation Summary: obp-abac-schema-examples-implementation-summary.md

Version: OBP API v6.0.0
Last Updated: 2024
Status: Production Ready