Implement enterprise role-based access control for Guidewire InsuranceSuite
including API roles, user permissions, and security policies.
Trigger with phrases like "guidewire rbac", "permissions guidewire",
"user roles", "api access control", "security permissions".
Implement enterprise role-based access control for Guidewire InsuranceSuite
including API roles, user permissions, and security policies.
Trigger with phrases like "guidewire rbac", "permissions guidewire",
"user roles", "api access control", "security permissions".
allowed-tools
Read, Write, Edit, Bash(curl:*), Grep
version
1.0.0
license
MIT
author
Jeremy Longshore <jeremy@intentsolutions.io>
Guidewire Enterprise RBAC
Overview
Implement comprehensive role-based access control for Guidewire InsuranceSuite including API roles, user permissions, system roles, and security policies.
// User role management
package gw.security.roles
uses gw.api.util.Logger
uses gw.pl.persistence.core.Bundle
class RoleManager {
private static final var LOG = Logger.forCategory("RoleManager")
// Assign role to user
static function assignRole(user : User, roleCode : String) {
var role = Role.get(roleCode)
if (role == null) {
throw new IllegalArgumentException("Role not found: ${roleCode}")
}
if (user.hasRole(role)) {
LOG.info("User ${user.UserName} already has role ${roleCode}")
return
}
gw.transaction.Transaction.runWithNewBundle(\bundle -> {
var u = bundle.add(user)
var userRole = new UserRole(bundle)
userRole.User = u
userRole.Role = role
LOG.info("Assigned role ${roleCode} to user ${user.UserName}")
})
}
// Remove role from user
static function removeRole(user : User, roleCode : String) {
var role = Role.get(roleCode)
if (role == null) {
throw new IllegalArgumentException("Role not found: ${roleCode}")
}
gw.transaction.Transaction.runWithNewBundle(\bundle -> {
var u = bundle.add(user)
var userRole = u.Roles.firstWhere(\ur -> ur.Role == role)
if (userRole != null) {
bundle.delete(userRole)
LOG.info("Removed role ${roleCode} from user ${user.UserName}")
}
})
}
// Check if user has permission
static function hasPermission(user : User, permission : String) : boolean {
return user.Roles.hasMatch(\ur ->
ur.Role.Permissions.hasMatch(\p -> p.Code == permission)
)
}
// Get all permissions for user
static function getUserPermissions(user : User) : Set<String> {
var permissions = new HashSet<String>()
user.Roles.each(\ur -> {
ur.Role.Permissions.each(\p -> {
permissions.add(p.Code)
})
})
return permissions
}
}
Step 4: Custom Permission Checks
// Custom permission framework
package gw.security.permissions
uses gw.api.util.Logger
uses gw.api.web.SessionUtil
class PermissionChecker {
private static final var LOG = Logger.forCategory("PermissionChecker")
// Check permission with audit logging
static function checkPermission(permission : String) : boolean {
var user = SessionUtil.CurrentUser
if (user == null) {
LOG.warn("Permission check failed: No user in session")
return false
}
var hasPermission = RoleManager.hasPermission(user, permission)
if (!hasPermission) {
LOG.warn("Permission denied: ${permission} for user ${user.UserName}")
auditPermissionDenial(user, permission)
}
return hasPermission
}
// Require permission (throws if denied)
static function requirePermission(permission : String) {
if (!checkPermission(permission)) {
throw new SecurityException("Permission denied: ${permission}")
}
}
// Check entity-level permission
static function canAccessEntity(entity : KeyableBean, operation : String) : boolean {
var user = SessionUtil.CurrentUser
if (user == null) {
return false
}
// Check ownership
if (isOwner(user, entity)) {
return true
}
// Check hierarchical access
if (hasHierarchicalAccess(user, entity)) {
return true
}
// Check role-based access
var permission = "${entity.IntrinsicType.Name}_${operation}"
return checkPermission(permission)
}
private static function isOwner(user : User, entity : KeyableBean) : boolean {
// Check if user created or is assigned to entity
if (entity typeis Policy) {
return entity.CreateUser == user
} else if (entity typeis Claim) {
return entity.AssignedUser == user
}
return false
}
private static function hasHierarchicalAccess(user : User, entity : KeyableBean) : boolean {
// Check organizational hierarchy
if (entity typeis Policy) {
var policyOrg = entity.ProducerCodeOfRecord?.Organization
return user.Organization == policyOrg || isParentOrg(user.Organization, policyOrg)
}
return false
}
private static function auditPermissionDenial(user : User, permission : String) {
// Log to audit trail
gw.api.audit.AuditLogger.log(
"PERMISSION_DENIED",
"User ${user.UserName} denied permission: ${permission}",
user.PublicID
)
}
}
Step 5: Row-Level Security
// Row-level security implementation
package gw.security.rls
uses gw.api.database.Query
uses gw.api.web.SessionUtil
class RowLevelSecurity {
// Apply security filters to queries
static function applySecurityFilter<T extends KeyableBean>(query : Query<T>) : Query<T> {
var user = SessionUtil.CurrentUser
if (user == null || user.hasRole(Role.get("SystemAdmin"))) {
return query // No filtering for system admins
}
var entityType = query.getTargetType()
if (entityType == Policy) {
return applyPolicySecurityFilter(query as Query<Policy>, user) as Query<T>
} else if (entityType == Claim) {
return applyClaimSecurityFilter(query as Query<Claim>, user) as Query<T>
} else if (entityType == Account) {
return applyAccountSecurityFilter(query as Query<Account>, user) as Query<T>
}
return query
}
private static function applyPolicySecurityFilter(
query : Query<Policy>,
user : User
) : Query<Policy> {
// Filter by user's organization or producer code
var userProducerCodes = user.ProducerCodes.map(\pc -> pc.Code)
if (!userProducerCodes.Empty) {
query.join(Policy#ProducerCodeOfRecord)
.compareIn(ProducerCode#Code, userProducerCodes)
}
return query
}
private static function applyClaimSecurityFilter(
query : Query<Claim>,
user : User
) : Query<Claim> {
// Filter by assigned user or group
var userGroups = user.GroupUsers.map(\gu -> gu.Group)
query.or(\orClause -> {
orClause.compare(Claim#AssignedUser, Equals, user)
if (!userGroups.Empty) {
orClause.compareIn(Claim#AssignedGroup, userGroups)
}
})
return query
}
private static function applyAccountSecurityFilter(
query : Query<Account>,
user : User
) : Query<Account> {
// Filter by producer code assignment
var userProducerCodes = user.ProducerCodes.map(\pc -> pc.PublicID)
if (!userProducerCodes.Empty) {
query.subselect(Account#ID, CompareIn,
Query.make(AccountProducerCode)
.compareIn(AccountProducerCode#ProducerCode, userProducerCodes)
.subselect(AccountProducerCode#Account, CompareIn, Account#ID)
)
}
return query
}
}
// Secured query helper
class SecuredQuery {
static function make<T extends KeyableBean>(type : Type<T>) : Query<T> {
var query = Query.make(type)
return RowLevelSecurity.applySecurityFilter(query)
}
}
// Usage
class PolicyService {
static function findPoliciesForCurrentUser() : List<Policy> {
// Automatically applies row-level security
return SecuredQuery.make(Policy)
.compare(Policy#Status, Equals, PolicyStatus.TC_INFORCE)
.select()
.toList()
}
}