External Role Mapping

Edge for Private Cloud v. 4.17.05

External Role Mapping lets you map your own groups or roles to role-based access control (RBAC) roles and groups created on Apigee Edge. 

Prerequisites

  • You must be an Apigee Private Cloud system administrator with global system admin credentials to perform this configuration. 
  • You need to know the root directory of your Apigee Edge Private Cloud installation. The default root directory is /opt. If you chose a different root directory during the Apigee Edge Private Cloud installation, use that instead of /opt as you follow these instructions.
  • Obtain the required JAR files from Apigee.

Ensure users are registered on Edge and in your directory service

When using role mapping, all users who access Edge must exist in both your external directory service and in the Edge user repository. That means when you add a user to your external directory service, you must also add that same user to the Apigee user repository.

For example, user a01@company.com exists in your external directory group 'apiadmin'. You then want to map user a01@company.com to the orgadmin role in Edge. Therefore, user a01@company.com must first be added to the orgadmin group on Edge. 

See Creating global users for more on creating Edge users and assigning them to roles.

Default configuration

External role mapping is disabled by default.

Enabling External Role Mapping

  1. Before you can complete the following configuration, you must create a Java class that implements the ExternalRoleMapperService interface. For details about this implementation, see the sample implementation below.
  2. Log into your Apigee Edge Management Server and then stop the Management Server:
    > /opt/apigee/apigee-service/bin/apigee-service edge-management-server stop
  3. Check the status of the servers. Be sure the Management Server is stopped/not running:
    > /opt/apigee/apigee-service/bin/apigee-all status
  4. Open /opt/apigee/customer/application/management-server.properties in a text editor.
  5. Edit the management-server.properties file with the following settings: 
    conf_security_authentication.user.store=externalized.authentication
    conf_security_externalized.authentication.role.mapper.enabled=true
    conf_security_externalized.authentication.role.mapper.implementation.class=com.customer.authorization.impl.ExternalRoleMapperImpl


    Important: The implementation class and package name referenced above, ExternalRoleMapperImpl, is only an example -- it is a class that you must implement and that you can name the class and package whatever you wish. For details about implementing this class, see the sample implementation below. 
  6. Save the management-server.properties file.
  7. Start the Management Server:
    > /opt/apigee/apigee-service/bin/apigee-service edge-management-server start
  8. Verify that the server is running:
    > /opt/apigee/apigee-service/bin/apigee-all status

Disabling External Authorization

To disable external authorization:

  1. Open /opt/apigee/customer/application/management-server.properties in a text editor.
  2. Change the authentication user store to ldap:
    conf_security_authentication.user.store=ldap
  3. Set the following property to false:
    conf_security_externalized.authentication.role.mapper.enabled=false
  4. Restart the Management Server:
    > /opt/apigee/apigee-service/bin/apigee-service edge-management-server restart

About the ExternalRoleMapperImpl sample implementation

In the management-server.properties config file described above, note the this line:

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

This class implements the ExternalRoleMapperService interface, and is required. You need to create your own implementation of this class that reflects your respective groups. When finished, place the compiled class in a JAR and put that JAR in /<install_dir>/apigee/edge-gateway/lib/infra/libraries

You can name the class and package whatever you wish as long as it implements ExternalRoleMapperService, is accessible in your classpath, and is referenced correctly in the management-server.properties config file. 

Below is a well-commented sample implementation of an ExternalRoleMapperImpl class. To compile this class, you must reference the following JAR file included with Edge:

/<install_dir>/apigee/edge-gateway/lib/infra/libraries/authentication-1.0.0.jar 
package com.apigee.authenticate;

import com.apigee.authentication.ConfigBean;
import com.apigee.authentication.ConnectionException;
import com.apigee.authentication.ExternalRoleMapperService;
import com.apigee.authentication.NameSpace;
import com.apigee.authentication.NameSpacedRole;
import com.apigee.authorization.namespace.OrganizationNamespace;
import com.apigee.authorization.namespace.SystemNamespace;
import java.util.Collection;
import java.util.HashSet;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

/** * 
 * Sample Implementation constructed with dummy roles with required namespaces.
 * 
 * Created by GopiAlagar on 6/12/15.
 */

public class ExternalRoleMapperImpl implements ExternalRoleMapperService {

    InitialDirContext dirContext = null;

    @Override
    public void stop() throws Exception {
    }

    /**
    * 
    * This method would be implemented by the customer, Below is the basic
    * example. 
    * 
    * If User has sysadmin role then it's expected to set SystemNameSpace 
    * along with the
    * res\quested NameSpace. Otherwise role's requestedNameSpace to be set 
    * for the NameSpacedRole.
    * 
    * Collection<NameSpacedRole> results = new HashSet<NameSpacedRole>();
    * 
    * NameSpacedRole sysNameSpace = new NameSpacedRole("sysadmin",
    * SystemNamespace.get());
    * 
    * String orgName =
    * ((OrganizationNamespace)requestedNameSpace).getOrganization();
    * 
    * NameSpacedRole orgNameSpace = new NameSpacedRole ("orgadmin",
    * requestedNameSpace);
    * 
    * results.add(sysNameSpace);
    * 
    * results.add(orgNameSpace);
    */

public Collection<NameSpacedRole> getUserRoles(String userName,
    String password, NameSpace requestedNameSpace) {

    /*
    * There are 3 actions performed in the below implementation
    * 1. Authenticate Given User against ADS
    * 2. Fetch the internal groups from the ADS
    * 3. Map the internal group into the apigee-edge roles
    */

    /*************************************************************/
    /******************* Authenticate Given User *******************/
    /*************************************************************/

    // Customer Specific Implementation will override this method
    // implementation.

    // Obtain dnName for given username or email address.
    String dnName = ImplementDnameLookupLogic();

    if (dnName == null) {
        System.out.println("Error ");
    }

    DirContext dirContext = null;

    Collection<NameSpacedRole> results = new HashSet<NameSpacedRole>();

    try {

        // Verify the credentials for a given username or dnName 
        // and password in order to create a directory context.
        dirContext = ImplementDirectoryContextCreationLogic();

        /****************************************************/
        /********** Fetch internal groups *******************/
        /****************************************************/

        String groupDN = "OU=Groups,DC=corp,DC=wacapps,DC=net";
        SearchControls controls = new SearchControls();
        controls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
        NamingEnumeration<SearchResult> groups = dirContext.search(groupDN,"(objectClass=*)", new Object[] { "", "" }, controls);

        if (groups.hasMoreElements()) {
            while (groups.hasMoreElements()) {
                SearchResult searchResult = groups.nextElement();
                Attributes attributes = searchResult.getAttributes();
                String groupName = attributes.get("name").get().toString();

                 /**************************************/
                 /** Map the internal group into the ***/
                 /** apigee-edge roles               ***/
                 /**************************************/

                if (groupName.equals("BusDev")) {
                    results.add(new NameSpacedRole("businessAdmin",SystemNamespace.get()));

                } else if (groupName.equals("DevSupport")) {
                    results.add(new NameSpacedRole("devOpsAdmin",SystemNamespace.get()));

                } else if (groupName.equals("Engineering")) {
                    if (requestedNameSpace instanceof OrganizationNamespace) {
                        String orgName = ((OrganizationNamespace) requestedNameSpace).getOrganization();
                        results.add(new NameSpacedRole("orgadmin", new OrganizationNamespace(orgName)));
                    }

                } else if (groupName.equals("Operations") || groupName.equals("IT")) {
                    results.add(new NameSpacedRole("sysadmin",SystemNamespace.get()));

                } else if (groupName.equals("Marketing")) {
                    results.add(new NameSpacedRole("marketAdmin",SystemNamespace.get()));

                } else {
                    results.add(new NameSpacedRole("readOnly",SystemNamespace.get()));
                }
            }

        } else {

            /** 
            * In case of no group found or exception found we throw empty
            * roles.
            */
            System.out.println(" !!!!! NO  GROUPS FOUND !!!!!");
        }

    } catch (Exception ex) {
        ex.printStackTrace();
        System.out.println("Error in authenticating User: {}" + new Object[] { userName });

    } finally {
        // Customer implementation to close 
        // ActiveDirectory/LDAP context.
    }

    return results;

}

@Override
public void start(ConfigBean arg0) throws ConnectionException {

    try {
        // Create InitialDirContext.
        // Create a directory context based on the 
        // system admin user credentials.
        dirContext = ImplementDirContextCreationLogicForSysAdmin();

        } catch (NamingException e) {
            // TODO Auto-generated catch block

            throw new ConnectionException(e);

        }

    }

}