Skip to main content

Migrating from LDAP to SAML

To facilitate migrating from Lightweight Directory Access Protocol (LDAP) to Security Assertion Markup Language (SAML), we provide a script that takes care of many of the required steps (i.e., moving tokens over and creating new principals (users) in the SAML realm).

Requirements and Steps

Before running the script, you must meet the following prerequisites:

  1. Ensure that your SAML users have the same username as your LDAP users.

  2. In your field mapping, you must set up roles/groups that map to the same roles/groups as exist in LDAP.

    1. If role names are different, you must create different external role mappings in Nexus Repository.

    2. If using external role mapping for LDAP, you will need to recreate them for SAML.

  3. Turn on scripting in $data-dir/etc/nexus.properties by adding nexus.scripts.allowCreation=true.

Now, you can run the script provided below. You can do this either through the REST API or by adding a script task through the user interface. If using a script task, put the code provided below as the script, set the schedule to manual, then run it and watch the logs.

Once finished, disable scripting again by removing nexus.scripts.allowCreation=true or setting this to false in the $data-dir/etc/nexus.properties.

You can test that the migration has worked by disabling the LDAP realm and confirming that a user token still works by trying a known user token.

LDAP to SAML Migration Script

import com.sonatype.nexus.usertoken.plugin.store.UserTokenStore
import org.apache.shiro.subject.SimplePrincipalCollection

UserTokenStore userTokenStore = container.lookup(UserTokenStore) as UserTokenStore
log.info('starting user token migration from LDAP to SAML')
userTokenStore.records().each { userTokenRecord ->
    log.info("Found token principal ${userTokenRecord.principals}")
    SimplePrincipalCollection newPrincipals = new SimplePrincipalCollection(userTokenRecord.principals)
    if (!newPrincipals.fromRealm('SamlRealm').empty) {
        log.info('skipping token as it already has SAML realm')
    }
    else if (!newPrincipals.fromRealm('LdapRealm').empty) {
      newPrincipals.add(newPrincipals.primaryPrincipal, 'SamlRealm')
        userTokenStore.remove(userTokenRecord.nameCode)
      try {
           def newUserTokenRecord = userTokenRecord.getClass().newInstance(newPrincipals, userTokenRecord.userToken, userTokenRecord.created)
           log.info('Adding SAML realm principal to token')
           log.debug("{}", newUserTokenRecord)
         userTokenStore.add(newUserTokenRecord)
      } catch (Exception e) {
         try {
            log.warn("Attempting to add back the original UserTokenRecord")
            def originalUserTokenRecord = userTokenRecord.getClass().newInstance(userTokenRecord.principals, userTokenRecord.userToken, userTokenRecord.created)
            log.debug("{}", originalUserTokenRecord)
            userTokenStore.add(originalUserTokenRecord)
         } catch (Exception e1) {
            log.error("Unable to add back the original UserTokenRecord", e1)
         }
         
         throw e;
      }
    }
    else {
        log.info('Skipping non-LDAP token')
    }
}

log.info('completed user token migration to SAML')