Uploaded image for project: 'OpenAM'
  1. OpenAM
  2. OPENAM-13407

AMIdentitySubject.isMember should not check privilege for group in different realm


    • Type: Bug
    • Status: Resolved
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 13.5.0, 14.0.0, 14.5.0, 6.0.0
    • Fix Version/s: 13.5.3, 6.5.0, 6.0.1, 5.5.2
    • Component/s: entitlements
    • Labels:
    • Sprint:
      AM Sustaining Sprint 53, AM Sustaining Sprint 54
    • Story Points:
    • Needs backport:
    • Support Ticket IDs:
    • Needs QA verification:
    • Functional tests:
    • Are the reproduction steps defined?:
      Yes and I used the same an in the description


      Bug description

      AMIdentitySubject.isMember should not check privilege for group in different realm

      User found policy evaluation performance issue when they were load testing using the following command against subrealm :

      curl --request POST \
      --header "Content-Type: application/json" \
      --header "Accept-API-Version:resource=2.0" \
      --header "iPlanetDirectoryPro: <admin user>" \
      --data '{
          "resources": [
          "application": "iPlanetAMWebAgentService",
          "subject": { "ssoToken": "<end user>"}
      }' \

      They noticed that the slowness is coming from the membership check against Active Directory which is configured as user datastore under top realm. Note that user belongs to /testrealm01 subrealm and admin group is under top realm in the below sample log entry

      amPolicy:07/27/2018 04:29:33:575 AM GMT: Thread[tomcat-http--1247,5,main]: TransactionId[...-1264]
      AMIndentitySubject.isMember(): checking membership with
      userDN = uid=testuser01,ou=testrealm01,ou=US,dc=openam,dc=forgerock,dc=org, subjectValue =

      AMIndentitySubject.isMember() eventually calls DJLDAPv3Repo.getMemberships() .

      Daemon Thread [http-bio-18080-exec-2] (Suspended (breakpoint at line 1475 in DJLDAPv3Repo))    
       owns: SocketWrapper<E>  (id=13301)    
       DJLDAPv3Repo.getMemberships(SSOToken, IdType, String, IdType) line: 1475    
       IdCachedServicesImpl(IdServicesImpl).getMemberships(SSOToken, IdType, String, IdType, String, String) line: 998    
       AMIdentity.isMember(AMIdentity) line: 1013    
       AMIdentitySubject.isMember(SSOToken) line: 382    
       PolicySubject.evaluate(String, SubjectAttributesManager, Subject, String, Map<String,Set<String>>) line: 219    
       OpenSSOPrivilege(Privilege).doesSubjectMatch(Subject, String, Subject, String, Map<String,Set<String>>) line: 669    
       OpenSSOPrivilege.internalEvaluate(Subject, String, Subject, String, String, Set<String>, Map<String,Set<String>>, boolean) line: 140    

      Audit/debug logs from performance test show slowness is caused by calls to lists of AMIdentitySubject.isMember to AD groups.
      Delegation permission is checked from top to bottom realm and this is because "Realm Admin" can create sub-realms, modify configurations for the realm's services and create, modify and delete Users, Groups, and Agents. However, user could be logged into /sub/sub realm. Therefore, delegation checks for admin groups under top realm for /sub/sub realm admin user should be skipped.

      How to reproduce the issue

      1. login to admin console and create /testrealm01 (NOTE: Configure Top Level Realm with slow external user datastore to see the issue)
        click [+New Realm] -> "Name: testrealm01" -> [Create] button
      2. under root realm, create a group "TestGroup01"
        click [Top Level Realm] -> [Identities] -> [Groups] -> [+Add Group]
        type "Group ID: TestGroup01" -> [Create] button
      3. under "/testrealm01", create another group "TestGroup02"
        click [testrealm01] -> [Identities] -> [Groups] -> [+Add Group]
        type "Group ID: TestGroup02" -> [Create] button
      4. under "/testrealm01", create user "testuser01"
        click [testrealm01] -> [Identities] -> [Groups] -> [+Add Identity]
        type "Id: testuser01" etc -> [Create] button
      5. assign all privileges to "TestGroup01"
        click [Top Level Realm] -> [Identities] -> [Groups] -> select "TestGroup01"
        click [Privileges] -> enable all privileges -> [Save Changes]
      6. assign all privileges to "TestGroup02"
        click [testrealm01] -> [Identities] -> [Groups] -> select "TestGroup02"
        click [Members] -> add "testuser01" -> [Save Changes]
        click [Privileges] -> enable all privileges -> [Save Changes]
      7. under "/testrealm01", create policy
        click [testrealm01] -> [PolicySets] -> [New Policy Set] -> [+New Policy Set]
        "Id: iPlanetAMWebAgentService", "Resource Types: URL" -> [Create]
        [+Add a Policy] -> "Name:TestPolicy01", "Resource Type: URL"
      8. login as "testuser01"
        curl --request POST --header "X-OpenAM-Username: testuser01" --header "X-OpenAM-Password: cangetin"  --header "Content-Type: application/json" --header "Accept-API-Version:protocol=1.0,resource=2.1" --data "{}"  "http://openam.example.com:18080/openam/json/realms/root/realms/testrealm01/authenticate"
      9. request policy evaluation as testuser01
        curl --request POST \
        --header "Accept-API-Version: resource=2.0" \
        --header "Content-Type: application/json" \
        --header "iPlanetDirectoryPro: <testuser01 token>" \
        --data '{
            "resources": [
            "application": "iPlanetAMWebAgentService",
            "subject": { "ssoToken": "<testuser01 token>"}. <---- better to use different token than admin user's token, but not absolutely necessary to recreate issue
        }' \

      You can see OpenAM will check if subject user has privilege against TestGroup01 under root realm.

      amPolicy:08/03/2018 06:12:43:584 AM NZST: Thread[entitlementThreadPool0,5,main]: TransactionId[edf6ca7c-c678-4de7-bb16-abe8a4f5d830-81]
      AMIdentitySubject.isMember: adding entry in SubjectEvaluationCache for , for userDN = id=testuser01,ou=user,o=testrealm01,ou=services,dc=openam,dc=forgerock,dc=org, subjectValue = id=TestGroup01,ou=group,dc=openam,dc=forgerock,dc=org, subjectMatch = false
      Expected behaviour
      AMIdentitySubject should not check if user belongs to a group under different realm than the user belongs to.
      Current behaviour
      AMIdentitySubject checks if user belongs to a group from top realm to subrealm.

      Work around

      Use amadmin token or Policy Agent token as AMIdentitySubject doesn't check membership if IdType is AGENT or if token belongs to super user

      Code analysis

      DataStore.searchPrivileges() will search all privileges from top realm. I think this could be because policies which should be applied to subrealm can now defined on the top realm? In any case, it may not be possible to change the filter and base DN of privilege search as it might affect normal policy evaluation.

      filter = (&(|(sunxmlKeyValue=hostindex=:\2f\2fdc=openam,dc=forgerock,dc=org)(sunxmlKeyValue=hostindex=:\2f\2fou=services,dc=openam,dc=forgerock,dc=org)(sunxmlKeyValue=hostindex=:\2f\2fo=testrealm01,ou=services,dc=openam,dc=forgerock,dc=org)(sunxmlKeyValue=hostindex=:\2f\2f))(|(sunxmlKeyValue=pathindex=\2frest\2f1.0)(sunxmlKeyValue=pathindex=\2frest\2f1.0\2fpolicies\2fevaluate)(sunxmlKeyValue=pathindex=\2frest\2f1.0\2fpolicies)(sunxmlKeyValue=pathindex=\2frest)(sunxmlKeyValue=pathindex=\2f)))
      baseDN = ou=default,ou=default,ou=OrganizationConfig,ou=1.0,ou=sunEntitlementIndexes,ou=services,o=sunamhiddenrealmdelegationservicepermissions,ou=services,dc=openam,dc=forgerock,dc=org

      AMIdentitySubject.isMember doesn't check if userIdentity (policy evaluation subject) and subjectIdentity (privilege) belongs to the same orgName. The check can be added around line 384.

                          } else if (
                                  = subjectIdType.canHaveMembers()) != null) 
                                  && allowedMemberTypes.contains(userIdType)) {
                              <<< --- orgDN check should be added --->> 
                              subjectMatch = userIdentity.isMember(subjectIdentity);
                              if (debug.messageEnabled()) {
                                          + "userIdentity type " + userIdType + 
                                          " can be a member of "
                                          + "subjectIdentityType " + subjectIdType
                                          + ":membership=" + subjectMatch);


          Issue Links



              • Assignee:
                sachiko Sachiko Wallace
                sachiko Sachiko Wallace
              • Votes:
                0 Vote for this issue
                11 Start watching this issue


                • Created: