External Role Mapping - Step by Step Guide

External Role Mapping V2- Step by Step Guide

External Role mapping is a new feature introduced in Apigee Edge 4.18.01 that allows you to map your corporate ldap groups to Apigee Edge roles. This is available only in Private cloud.

This article explains step by step guide to setting up External Role Mapping in Apigee Edge. I assume you have setup Apigee Edge private cloud 4.18.01.

Step 0 : External(Corp) LDAP Setup

Let’s assume the external LDAP DSE looks like as shown below :


In this example, the BASE DN is dc=tech-brief,dc=apigee-demo,dc=net. There are three groups sysadmin, Eng and BusDev defined in LDAP and users are associated with these groups.

For ex , the BusDev attributes would look like this :

Similarly a test5@apigee-demo.net user attributes looks like this :


I have also created sysadmin for Apigee Edge - opdk@apigee.com as a user in External LDAP. For simplicity, I have kept the ldap password for opdk@apigee.com same as that I had set during Apigee Edge setup.

Step 1 :Setup Apigee Edge with external LDAP authentication

For External Role mapping to work, you need to first setup Apigee Edge with External LDAP authentication. You can refer here for more details about how to set up.


To setup external ldap authentication, add following properties in /opt/apigee/customer/application/management-server.properties

conf_security_authentication.user.store=externalized.authentication
## Required to enable the external authorization feature. Do not change it.
conf_security_externalized.authentication.implementation.class=com.apigee.rbac.impl.LdapAuthenticatorImpl
conf_security_externalized.authentication.bind.direct.type=false
## The next seven properties are needed regardless of direct or indirect binding. You need to configure these per your external LDAP installation. 
## The IP or domain for your external LDAP instance. 
conf_security_externalized.authentication.server.url=ldap://tech-brief-ldap.apigee-demo.net:389
## Replace with your external LDAP server version.
conf_security_externalized.authentication.server.version=3
## Set the server timeout in milliseconds. 
conf_security_externalized.authentication.server.conn.timeout=50000
conf_security_externalized.authentication.user.store.baseDN=dc=tech-brief,dc=apigee-demo,dc=net
## Do not change this search string. It is used internally. 
conf_security_externalized.authentication.user.store.search.query=(&(${userAttribute}=${userId}))
conf_security_externalized.authentication.user.store.user.attribute=mail
conf_security_externalized.authentication.user.store.user.email.attribute=mail
conf_security_externalized.authentication.indirect.bind.server.admin.dn=mail=opdk@apigee.com,ou=users,ou=global,dc=tech-brief,dc=apigee-demo,dc=net
conf_security_externalized.authentication.indirect.bind.server.admin.password=XXXXXXX
conf_security_externalized.authentication.indirect.bind.server.admin.password.encrypted=false

Restart management server to take affect these properties. This will setup external apigee edge with External LDAP authentication with indirect binding. I assume that opdk@apigee.com is sysadmin for Apigee Edge and that user is also present in External LDAP.

Test the external LDAP authentication by logging with LDAP password of users created in Apigee Edge.

Step 2 : Java Rolemapper Implementation

Create a Java class that implements ExternalRoleMapperServiceV2 interface. Refer here for more details.

An example java class is given below

package com.customer.authorization.impl;
import com.apigee.authentication.*;
import com.apigee.authorization.namespace.OrganizationNamespace;
import com.apigee.authorization.namespace.SystemNamespace;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Hashtable;
import java.util.HashMap;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.*;
public class ExternalRoleMapperImpl implements ExternalRoleMapperServiceV2{
    private static final String DEFAULT_LDAP_INTIAL_CONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
    private static final String DEFAULT_AUTHENTICATION_TYPE = "simple";
    private static final String DEFAULT_LDAP_URL = "ldap://tech-brief-ldap.apigee-demo.net:389";
    private static final String ADMIN_DN = "mail=opdk@apigee.com,ou=users,ou=global,dc=tech-brief,dc=apigee-demo,dc
=net";
    private static final String ADMIN_SECRET = "Secret123";
    private static final String groupDN = "ou=Group,ou=global,dc=tech-brief,dc=apigee-demo,dc=net";
    private static final String GROUP = "Group";
    private static final String DEFAULT_ORG = "tech-brief";
    private DirContext initialDirContext;
    private SearchControls controls = new SearchControls();

    @Override
    public Collection<NameSpacedRole> getUserRoles(String username, String password, String requestedUsername, NameSpace expectedNamespace) throws ExternalRoleMappingException {
        return getUserRoles(requestedUsername, expectedNamespace);
    }


    @Override
    public Collection<NameSpacedRole> getUserRoles(String username, NameSpace expectedNamespace) throws ExternalRoleMappingException {
        Collection<NameSpacedRole> roles = new HashSet<>();
        String orgName = "tech-brief";
        System.out.println("Getting Group");


        String userGroupFilter = "(memberUid=uid)";
        controls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
        try {
            /***************************************************/
            /************** Fetch groups for user **************/
            /***************************************************/
            NamingEnumeration<SearchResult> groupResults = initialDirContext.search(groupDN, userGroupFilter.replace("uid", username), new Object[] { "", "" }, controls);
            while (groupResults.hasMoreElements()) {
                SearchResult searchResult = groupResults.nextElement();
                Attributes attributes = searchResult.getAttributes();
                String groupName = attributes.get("cn").get().toString();


                if (groupName.equals("BusDev")) {
                   roles.add(new NameSpacedRole("businessuser",new OrganizationNamespace(orgName)));
                } else if (groupName.equals("Eng")) {
                    roles.add(new NameSpacedRole("user",new OrganizationNamespace(orgName)));
                } else if (groupName.equals("sysadmin")) {
                    roles.add(new NameSpacedRole("orgadmin",new OrganizationNamespace(orgName)));
                    roles.add(new NameSpacedRole("sysadmin",SystemNamespace.get()));
                } else {
                    roles.add(new NameSpacedRole("user", new OrganizationNamespace(orgName)));
                }


                //groups.add(groupName);
            }
        } catch (NamingException e) {
            e.printStackTrace();
            throw new ExternalTeamMappingException(e);
        }
        return roles;


    }
    @Override
    public Collection<String> getUsersForRole(String roleName, NameSpace expectedNamespace) throws ExternalRoleMappingException {
        
        //Collection<String> members = new HashSet<>();
        Collection<String> users = new HashSet<>();
        String groupName="";


        if (roleName.equalsIgnoreCase("sysadmin")) {
            groupName = "sysadmin";
        } else if(roleName.equalsIgnoreCase("orgadmin")) {
            groupName = "sysadmin";
        } else if (roleName.equalsIgnoreCase("user")) {
            groupName = "Eng";
        } else if (roleName.equalsIgnoreCase("businessuser")) {
            groupName = "BusDev";
        }


        String groupFilter = "(cn=groupName)";
        controls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
        try{
            NamingEnumeration<SearchResult> groupResults = initialDirContext.search(groupDN, groupFilter.replace("groupName", groupName), new Object[] { "", "" }, controls);
            while (groupResults.hasMoreElements()) {
                SearchResult searchResult = groupResults.nextElement();
                Attributes attributes = searchResult.getAttributes();
                if (attributes.get("memberUid") == null) {
                    continue;
                }
                NamingEnumeration<?> memberUids = attributes.get("memberUid").getAll();
                while (memberUids.hasMoreElements()) {
                    users.add(memberUids.next().toString());
                }
            }
        } catch (NamingException e) {
            e.printStackTrace();
            throw new ExternalTeamMappingException(e);
        }
        return users;

    }
    @Override
    public void start(ConfigBean configBean) throws ConnectionException {


        Hashtable<String, String> environment = new Hashtable<>();
        environment.put(Context.INITIAL_CONTEXT_FACTORY, DEFAULT_LDAP_INTIAL_CONTEXT_FACTORY);
        environment.put(Context.SECURITY_AUTHENTICATION, DEFAULT_AUTHENTICATION_TYPE);
        environment.put(Context.SECURITY_PRINCIPAL, ADMIN_DN);
        environment.put(Context.SECURITY_CREDENTIALS, ADMIN_SECRET);
        environment.put(Context.PROVIDER_URL, DEFAULT_LDAP_URL);
        // connect to LDAP
        try {
            initialDirContext = new InitialDirContext(environment);
        } catch (NamingException e) {
            e.printStackTrace();
        }
        
    }
    @Override
    public void stop() throws Exception {
    }
    @Override
    public Collection<NameSpacedRole> getUserRoles(String username, String password, NameSpace expectedNamespace) throws ExternalRoleMappingException {
        return getUserRoles(username, expectedNamespace);
    }
}

We are mapping Eng group of LDAP to users role and BusDev group to businessuser role of Apigee Edge. You can write complex mapping by overriding these methods.We have initialized LDAPContext with external LDAP details and overridden two methods - getUserRoles and getUserForRoles.

Take this code sample from above and put in a following directory structure in management server


Compile the code and create jar files and move the created jar file to /opt/apigee/edge-management-server/lib/thirdparty/

$ cd tech-brief/java
$ javac -d bin -sourcepath src -cp /opt/apigee/edge-management-server/lib/infra/libraries/authentication-1.0.0.jar src/com/customer/authorization/impl/ExternalRoleMapperImpl.java
$ cd bin
$ jar cvf externalrolemapper.jar *
$ mv externalrolemapper.jar /opt/apigee/edge-management-server/lib/thirdparty/externalrolemapper.jar

Step 3 : Setup External Role Mapping Settings in Management Server

The next step is to update management-server.properties you had set in step 1 to support External Authorization

Add following properties in /opt/apigee/customer/application/management-server.properties

conf_security_externalized.authentication.role.mapper.enabled=trueconf_security_externalized.authentication.role.mapper.implementation.class=com.customer.authorization.impl.ExternalRoleMapperImpl

Restart Management Server

Step 4 : How to Test

  • Add a user say test9@apigee-demo.net in External LDAP and associate it with Eng Group.
  • Login Apigee Edge UI with Org Admin credentials.
  • Add a user test9@apigee-demo.net from Admin->Users console and assign it to Org Admin Role. This step adds new user in Apigee Edge.
  • Remove Users Role from that Org so that the new user doesn’t have any associated role.

Logout and try logging Apigee Edge with new user (test9@apigee-demo.net). test9 now is associated with Users role of Apigee Edge.

Comments
dwctua
Explorer

@Rajesh, is there a way to skip the user creation? I'm thinking the step to create user manually is not really needed, user should be able to login as long as it is authenticated and mapped to a role.

paulmooney
Participant II

@Rajesh,

Is it possible to create LDAP resource for external role mapping while using apigee-sso with IdP for authentication?

In your write up it says edge needs to be configured for LDAP authentication, could it be instead be configured for LDAP queries?

example like:

User authenticates with apigee-sso and IdP,

IdP returns saml assertion edge-sso

edge-sso redirects to edgeui

management server LDAP query against authenticated user email

management server maps external group role to user

user authorized for edge role

Thank you for providing this write up.

manjunath-undi
Observer

A similar question to Paul's.

User authentication to login to Edge UI using apigee SSO and IDP
But, role mapping is managed with external role mapping with AD
Is the combination possible?

Version history
Last update:
‎02-15-2018 06:26 PM
Updated by: