guidewire-enterprise-rbac

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Guidewire Enterprise RBAC

Guidewire 企业级RBAC

Overview

概述

Implement comprehensive role-based access control for Guidewire InsuranceSuite including API roles, user permissions, system roles, and security policies.
为Guidewire InsuranceSuite实现全面的基于角色的访问控制(RBAC),涵盖API角色、用户权限、系统角色及安全策略。

Prerequisites

前提条件

  • Access to Guidewire Cloud Console (GCC)
  • Understanding of OAuth2 and JWT
  • Knowledge of enterprise security patterns
  • 拥有Guidewire Cloud Console(GCC)的访问权限
  • 了解OAuth2和JWT相关知识
  • 熟悉企业安全模式

RBAC Architecture

RBAC架构

┌─────────────────────────────────────────────────────────────────────────────────┐
│                         Guidewire RBAC Architecture                              │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │                         Guidewire Hub (IdP)                              │   │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐    │   │
│  │  │   Users     │  │   Groups    │  │ Applications│  │   Roles     │    │   │
│  │  │             │  │             │  │             │  │             │    │   │
│  │  │ • Internal  │  │ • AD Sync   │  │ • Browser   │  │ • API Roles │    │   │
│  │  │ • External  │  │ • Manual    │  │ • Service   │  │ • App Roles │    │   │
│  │  └─────────────┘  └─────────────┘  └─────────────┘  └─────────────┘    │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                        │                                         │
│                    ┌───────────────────┼───────────────────┐                    │
│                    │                   │                   │                    │
│                    ▼                   ▼                   ▼                    │
│  ┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐ │
│  │     PolicyCenter      │ │     ClaimCenter       │ │    BillingCenter      │ │
│  │                       │ │                       │ │                       │ │
│  │ System Roles:         │ │ System Roles:         │ │ System Roles:         │ │
│  │ • Underwriter         │ │ • Claims Adjuster     │ │ • Billing Admin       │ │
│  │ • Policy Admin        │ │ • Claims Supervisor   │ │ • Payment Handler     │ │
│  │ • Agent               │ │ • SIU Investigator    │ │ • Collections Agent   │ │
│  │                       │ │                       │ │                       │ │
│  │ API Roles:            │ │ API Roles:            │ │ API Roles:            │ │
│  │ • pc_policy_read      │ │ • cc_claim_read       │ │ • bc_billing_read     │ │
│  │ • pc_policy_admin     │ │ • cc_claim_admin      │ │ • bc_payment_admin    │ │
│  └───────────────────────┘ └───────────────────────┘ └───────────────────────┘ │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────┐
│                         Guidewire RBAC Architecture                              │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │                         Guidewire Hub (IdP)                              │   │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐    │   │
│  │  │   Users     │  │   Groups    │  │ Applications│  │   Roles     │    │   │
│  │  │             │  │             │  │             │  │             │    │   │
│  │  │ • Internal  │  │ • AD Sync   │  │ • Browser   │  │ • API Roles │    │   │
│  │  │ • External  │  │ • Manual    │  │ • Service   │  │ • App Roles │    │   │
│  │  └─────────────┘  └─────────────┘  └─────────────┘  └─────────────┘    │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                        │                                         │
│                    ┌───────────────────┼───────────────────┐                    │
│                    │                   │                   │                    │
│                    ▼                   ▼                   ▼                    │
│  ┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐ │
│  │     PolicyCenter      │ │     ClaimCenter       │ │    BillingCenter      │ │
│  │                       │ │                       │ │                       │ │
│  │ System Roles:         │ │ System Roles:         │ │ System Roles:         │ │
│  │ • Underwriter         │ │ • Claims Adjuster     │ │ • Billing Admin       │ │
│  │ • Policy Admin        │ │ • Claims Supervisor   │ │ • Payment Handler     │ │
│  │ • Agent               │ │ • SIU Investigator    │ │ • Collections Agent   │ │
│  │                       │ │                       │ │                       │ │
│  │ API Roles:            │ │ API Roles:            │ │ API Roles:            │ │
│  │ • pc_policy_read      │ │ • cc_claim_read       │ │ • bc_billing_read     │ │
│  │ • pc_policy_admin     │ │ • cc_claim_admin      │ │ • bc_payment_admin    │ │
│  └───────────────────────┘ └───────────────────────┘ └───────────────────────┘ │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘

Instructions

操作步骤

Step 1: Configure API Roles in GCC

步骤1:在GCC中配置API角色

yaml
undefined
yaml
undefined

API Role Configuration

API Role Configuration

Guidewire Cloud Console > Identity & Access > API Roles

Guidewire Cloud Console > Identity & Access > API Roles

api_roles:

Read-only roles

  • name: pc_policy_read application: PolicyCenter description: Read-only access to policies and accounts permissions:
    • endpoint: /account/v1/accounts operations: [GET]
    • endpoint: /account/v1/accounts/{id} operations: [GET]
    • endpoint: /policy/v1/policies operations: [GET]
    • endpoint: /policy/v1/policies/{id} operations: [GET]

Admin roles

  • name: pc_policy_admin application: PolicyCenter description: Full access to policy administration permissions:
    • endpoint: /account/v1/accounts operations: [GET, POST, PATCH]
    • endpoint: /job/v1/submissions operations: [GET, POST, PATCH]
    • endpoint: /job/v1/submissions/{id}/quote operations: [POST]
    • endpoint: /job/v1/submissions/{id}/bind operations: [POST]
    • endpoint: /policy/v1/policies operations: [GET, POST, PATCH]

Claims roles

  • name: cc_claim_admin application: ClaimCenter description: Full access to claims management permissions:
    • endpoint: /claim/v1/claims operations: [GET, POST, PATCH]
    • endpoint: /fnol/v1/fnol operations: [POST]
    • endpoint: /claim/v1/claims/{id}/exposures operations: [GET, POST, PATCH]
    • endpoint: /claim/v1/claims/{id}/payments operations: [GET, POST]
undefined
api_roles:

Read-only roles

  • name: pc_policy_read application: PolicyCenter description: Read-only access to policies and accounts permissions:
    • endpoint: /account/v1/accounts operations: [GET]
    • endpoint: /account/v1/accounts/{id} operations: [GET]
    • endpoint: /policy/v1/policies operations: [GET]
    • endpoint: /policy/v1/policies/{id} operations: [GET]

Admin roles

  • name: pc_policy_admin application: PolicyCenter description: Full access to policy administration permissions:
    • endpoint: /account/v1/accounts operations: [GET, POST, PATCH]
    • endpoint: /job/v1/submissions operations: [GET, POST, PATCH]
    • endpoint: /job/v1/submissions/{id}/quote operations: [POST]
    • endpoint: /job/v1/submissions/{id}/bind operations: [POST]
    • endpoint: /policy/v1/policies operations: [GET, POST, PATCH]

Claims roles

  • name: cc_claim_admin application: ClaimCenter description: Full access to claims management permissions:
    • endpoint: /claim/v1/claims operations: [GET, POST, PATCH]
    • endpoint: /fnol/v1/fnol operations: [POST]
    • endpoint: /claim/v1/claims/{id}/exposures operations: [GET, POST, PATCH]
    • endpoint: /claim/v1/claims/{id}/payments operations: [GET, POST]
undefined

Step 2: Service Account Configuration

步骤2:服务账号配置

typescript
// Service account management
interface ServiceAccount {
  clientId: string;
  name: string;
  description: string;
  apiRoles: string[];
  environments: string[];
}

const serviceAccounts: ServiceAccount[] = [
  {
    clientId: 'integration-service-prod',
    name: 'Integration Service',
    description: 'Backend integration service for policy and claims sync',
    apiRoles: ['pc_policy_admin', 'cc_claim_read'],
    environments: ['production']
  },
  {
    clientId: 'agent-portal-prod',
    name: 'Agent Portal',
    description: 'Agent-facing portal application',
    apiRoles: ['pc_policy_read', 'pc_submission_handler'],
    environments: ['production', 'uat']
  },
  {
    clientId: 'reporting-service',
    name: 'Reporting Service',
    description: 'Read-only access for reporting',
    apiRoles: ['pc_policy_read', 'cc_claim_read', 'bc_billing_read'],
    environments: ['production']
  }
];

// Register service account in GCC
async function registerServiceAccount(account: ServiceAccount): Promise<void> {
  const response = await gccClient.post('/api/v1/applications', {
    clientId: account.clientId,
    name: account.name,
    description: account.description,
    type: 'service',
    apiRoles: account.apiRoles.map(role => ({ name: role }))
  });

  console.log(`Registered service account: ${account.clientId}`);
}
typescript
// Service account management
interface ServiceAccount {
  clientId: string;
  name: string;
  description: string;
  apiRoles: string[];
  environments: string[];
}

const serviceAccounts: ServiceAccount[] = [
  {
    clientId: 'integration-service-prod',
    name: 'Integration Service',
    description: 'Backend integration service for policy and claims sync',
    apiRoles: ['pc_policy_admin', 'cc_claim_read'],
    environments: ['production']
  },
  {
    clientId: 'agent-portal-prod',
    name: 'Agent Portal',
    description: 'Agent-facing portal application',
    apiRoles: ['pc_policy_read', 'pc_submission_handler'],
    environments: ['production', 'uat']
  },
  {
    clientId: 'reporting-service',
    name: 'Reporting Service',
    description: 'Read-only access for reporting',
    apiRoles: ['pc_policy_read', 'cc_claim_read', 'bc_billing_read'],
    environments: ['production']
  }
];

// Register service account in GCC
async function registerServiceAccount(account: ServiceAccount): Promise<void> {
  const response = await gccClient.post('/api/v1/applications', {
    clientId: account.clientId,
    name: account.name,
    description: account.description,
    type: 'service',
    apiRoles: account.apiRoles.map(role => ({ name: role }))
  });

  console.log(`Registered service account: ${account.clientId}`);
}

Step 3: User Role Management in Gosu

步骤3:在Gosu中管理用户角色

gosu
// 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
  }
}
gosu
// 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

步骤4:自定义权限校验

gosu
// 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
    )
  }
}
gosu
// 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

步骤5:行级安全控制

gosu
// 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()
  }
}
gosu
// 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()
  }
}

Step 6: API Authorization Middleware

步骤6:API授权中间件

typescript
// API authorization middleware
import { Request, Response, NextFunction } from 'express';

interface SecurityContext {
  userId: string;
  roles: string[];
  apiRoles: string[];
  organizationId: string;
  producerCodes: string[];
}

// Extract security context from JWT
function extractSecurityContext(token: JWTPayload): SecurityContext {
  return {
    userId: token.sub,
    roles: token.roles || [],
    apiRoles: token.api_roles || [],
    organizationId: token.org_id,
    producerCodes: token.producer_codes || []
  };
}

// Require specific API role
function requireApiRole(...requiredRoles: string[]) {
  return (req: Request, res: Response, next: NextFunction) => {
    const context = (req as any).securityContext as SecurityContext;

    if (!context) {
      return res.status(401).json({ error: 'Unauthorized' });
    }

    const hasRequiredRole = requiredRoles.some(role =>
      context.apiRoles.includes(role)
    );

    if (!hasRequiredRole) {
      return res.status(403).json({
        error: 'Forbidden',
        message: 'Insufficient API role permissions',
        requiredRoles,
        userRoles: context.apiRoles
      });
    }

    next();
  };
}

// Row-level security filter for API responses
function applySecurityFilter<T>(
  data: T[],
  context: SecurityContext,
  filterFn: (item: T, context: SecurityContext) => boolean
): T[] {
  if (context.roles.includes('SystemAdmin')) {
    return data;
  }
  return data.filter(item => filterFn(item, context));
}

// Usage in routes
app.get('/api/policies',
  authMiddleware,
  requireApiRole('pc_policy_read', 'pc_policy_admin'),
  async (req, res) => {
    const context = (req as any).securityContext;

    let policies = await guidewireClient.getPolicies();

    // Apply row-level security
    policies = applySecurityFilter(policies, context, (policy, ctx) => {
      return ctx.producerCodes.includes(policy.producerCode) ||
             ctx.organizationId === policy.organizationId;
    });

    res.json(policies);
  }
);
typescript
// API authorization middleware
import { Request, Response, NextFunction } from 'express';

interface SecurityContext {
  userId: string;
  roles: string[];
  apiRoles: string[];
  organizationId: string;
  producerCodes: string[];
}

// Extract security context from JWT
function extractSecurityContext(token: JWTPayload): SecurityContext {
  return {
    userId: token.sub,
    roles: token.roles || [],
    apiRoles: token.api_roles || [],
    organizationId: token.org_id,
    producerCodes: token.producer_codes || []
  };
}

// Require specific API role
function requireApiRole(...requiredRoles: string[]) {
  return (req: Request, res: Response, next: NextFunction) => {
    const context = (req as any).securityContext as SecurityContext;

    if (!context) {
      return res.status(401).json({ error: 'Unauthorized' });
    }

    const hasRequiredRole = requiredRoles.some(role =>
      context.apiRoles.includes(role)
    );

    if (!hasRequiredRole) {
      return res.status(403).json({
        error: 'Forbidden',
        message: 'Insufficient API role permissions',
        requiredRoles,
        userRoles: context.apiRoles
      });
    }

    next();
  };
}

// Row-level security filter for API responses
function applySecurityFilter<T>(
  data: T[],
  context: SecurityContext,
  filterFn: (item: T, context: SecurityContext) => boolean
): T[] {
  if (context.roles.includes('SystemAdmin')) {
    return data;
  }
  return data.filter(item => filterFn(item, context));
}

// Usage in routes
app.get('/api/policies',
  authMiddleware,
  requireApiRole('pc_policy_read', 'pc_policy_admin'),
  async (req, res) => {
    const context = (req as any).securityContext;

    let policies = await guidewireClient.getPolicies();

    // Apply row-level security
    policies = applySecurityFilter(policies, context, (policy, ctx) => {
      return ctx.producerCodes.includes(policy.producerCode) ||
             ctx.organizationId === policy.organizationId;
    });

    res.json(policies);
  }
);

Role Matrix

角色矩阵

RolePolicyCenterClaimCenterBillingCenter
System AdminFull AccessFull AccessFull Access
UnderwriterSubmissions, QuotesRead OnlyRead Only
Claims AdjusterRead OnlyClaims, PaymentsRead Only
Billing AdminRead OnlyRead OnlyFull Access
AgentSubmissions, ReadFNOL OnlyRead Only
AuditorRead OnlyRead OnlyRead Only
角色PolicyCenterClaimCenterBillingCenter
系统管理员完全访问权限完全访问权限完全访问权限
核保人投保申请、报价只读权限只读权限
理赔调整员只读权限理赔、支付只读权限
账单管理员只读权限只读权限完全访问权限
代理人投保申请、只读仅FNOL(首次通知损失)只读权限
审计员只读权限只读权限只读权限

Best Practices

最佳实践

PracticeDescription
Least PrivilegeGrant minimum necessary permissions
Role SeparationSeparate roles by function, not convenience
Regular AuditsReview role assignments quarterly
Service AccountsUse dedicated accounts for integrations
API Role ScopingScope API roles to specific endpoints
实践说明
最小权限原则仅授予完成工作所需的最小权限
角色分离按职能划分角色,而非出于便利性合并
定期审计每季度审核角色分配情况
专用服务账号为集成场景使用专用服务账号
API角色范围限定为API角色限定特定端点的访问权限

Output

输出成果

  • API role configuration
  • Service account setup
  • User role management
  • Custom permission framework
  • Row-level security
  • Authorization middleware
  • API角色配置
  • 服务账号设置
  • 用户角色管理模块
  • 自定义权限框架
  • 行级安全控制实现
  • 授权中间件

Resources

参考资源

Next Steps

后续步骤

For migration strategies, see
guidewire-migration-deep-dive
.
如需了解迁移策略,请查看「guidewire-migration-deep-dive」。