mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 13:07:02 +00:00
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.
398 lines
9.9 KiB
Markdown
398 lines
9.9 KiB
Markdown
# 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:**
|
|
|
|
```scala
|
|
// 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:**
|
|
|
|
```scala
|
|
// 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:**
|
|
|
|
```scala
|
|
// 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:**
|
|
|
|
```scala
|
|
// 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:**
|
|
|
|
```scala
|
|
// 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:**
|
|
|
|
```scala
|
|
// 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:**
|
|
|
|
```scala
|
|
// 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:**
|
|
|
|
```scala
|
|
// 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:**
|
|
|
|
```scala
|
|
// 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:**
|
|
|
|
```scala
|
|
// 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:**
|
|
|
|
```scala
|
|
// 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:**
|
|
|
|
```scala
|
|
// ✅ 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
|
|
```scala
|
|
customerAttributes.exists(ca => ca.name == "credit_score" && ca.value.toInt > 650) &&
|
|
accountOpt.exists(_.balance > 5000) &&
|
|
!transactionAttributes.exists(_.name == "fraud_flag")
|
|
```
|
|
|
|
### Wire Transfer Authorization
|
|
```scala
|
|
transactionOpt.exists(t => t.amount < 100000 && t.transactionType.exists(_.contains("WIRE"))) &&
|
|
authenticatedUserAttributes.exists(_.name == "wire_authorized" && _.value == "true")
|
|
```
|
|
|
|
### Joint Account Access
|
|
```scala
|
|
accountOpt.exists(a => a.accountHolders.exists(h =>
|
|
h.userId == authenticatedUser.userId ||
|
|
h.emailAddress == authenticatedUser.emailAddress
|
|
))
|
|
```
|
|
|
|
### Account Closure (Self-service or Manager)
|
|
```scala
|
|
accountOpt.exists(a =>
|
|
(a.balance == 0 && userOpt.exists(_.userId == authenticatedUser.userId)) ||
|
|
authenticatedUserAttributes.exists(_.name == "role" && _.value == "manager")
|
|
)
|
|
```
|
|
|
|
### VIP Priority Processing
|
|
```scala
|
|
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
|
|
```scala
|
|
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
|
|
```scala
|
|
// WRONG - Snake case
|
|
user.user_id
|
|
account.account_id
|
|
user.email_address
|
|
|
|
// CORRECT - Camel case
|
|
user.userId
|
|
account.accountId
|
|
user.emailAddress
|
|
```
|
|
|
|
### ❌ Wrong Parameter Names
|
|
```scala
|
|
// 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
|
|
```scala
|
|
// 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:
|
|
|
|
```bash
|
|
curl -X GET \
|
|
https://your-obp-instance/obp/v6.0.0/management/abac-rules-schema \
|
|
-H 'Authorization: DirectLogin token=YOUR_TOKEN'
|
|
```
|
|
|
|
---
|
|
|
|
## Related Documentation
|
|
|
|
- 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 ✅
|