25 thoughts on “Custom External Login Module

  1. Hi Lokesh ,

    Thanks for your post , It has given me good insight about custom login module ,
    I have an LDAP user who is already logged in , It creates local AEM user in AEM useradmin
    Lets say few properties of these logged in user are changed in ldap server , If I need to sync these changes with AEM , I can go to jmx console and sync the users ,but is there any approach to sync these changes programatically ?

    I could see syncUser method in customExternalModule .java ,it is expecting ExternalUser as parameter , Can I call this method to sync user , if so how to get reference of ExternalUser for current logged in user ? I tried with idp.getUser(userid) but no luck.

    Any pointer would be highly helpful


  2. SyncUser in the CustomExternalLoginModule is the method which is called while login() and sync the user if it is not synced to AEM already !!

    So you might have to change the logic in the login() method to call the syncUser as idp user will be available. Let me know your usecase and if you cannot go forward and I will give it a try !

  3. HI Lokesh ,
    Thanks for reply , Below is my usecase
    User clicks register button on website running on AEM ,As part of registration I would capture user details and create user in ldap server via code , user would login using login component which is customly developed , After that user would have option to visit his profile page and updates his/her details . If user changes his firstname/lastname/email , i will have to update them in ldap server. These changes should be immediately reflected/sync in AEM .
    In order to achieve this I need to sync user immediately after he updates his profile details,

    I can achieve this by doing some settings at sync handler in OSGI level
    but with this approach user has to logout and login again to see his changes in AEM

    1. As you mentioned, sync happens using ‘SyncHandler’. If you need to customize, then you will have to write your own syncHandler and use it with your customLoginModule or if OOB works for you, then use OOB ExternalLoginModule.
      I will shortly write about how to write our own SyncHandler!

      1. Hi Lokesh,

        Really informative blog. Very often I refer your blog to check new stuff in AEM.

        As above mentioned, have you had a chance to customize the SyncHandler. My need is to use OOTB SyncHandler for to sync users and write custom code to synchronize users group membership in AEM.
        in 5.6 – I was using “com.day.crx.security.ldap.sync.Callback” to synchronize groups after the users is synchronized.

        Any help is really appreciated.

        1. In the customExternalLoginModule example given above, contains a method called ‘syncUsers’ which essentially you can customize. Are you looking at anything more than that ?
          We have however write our own customSyncHandler by extending ‘SyncHandler’ interface

          1. Thanks for your quick response.

            Here is my code snippet from AEM 5.6 which is used to update user group membership
            * This method is called after a user had been synchronized from the
            * directory server with CRX. All the configured LDAP attribute to JCR
            * properties mappings have already been applied on the user.
            * @param session the current JackrabbitSession object
            * @param user the user that was synchronized with the directory
            * server.
            * @param attributes the attributes on the user node from the directory
            * server.
            * @param vf the value factory to create additional value.
            * @throws RepositoryException if an error occurs.
            public void onUserSync(JackrabbitSession session, User user,
            Map attributes, ValueFactory vf) throws RepositoryException {

            As a way to work around slow LDAP group query response times, this code
            maintains the user/group membership using the uniqueMemberOf property of the
            users profile. uniqueMemberOf is sync’ed from LDAP and contains an up-to-date
            list of group membership.

            To enable this callback, add the following attributes to AEMs conf/ldap.conf:


            String userProfilePath = user.getPath() + “/profile”;
            Node userProfile = session.getNode(userProfilePath);

            // fetch the LDAP group membership
            Value[] uniqueMemberOf = userProfile.getProperty(“uniqueMemberOf”).getValues();

            // ADD ldap group membership
            Iterator iGroup = user.declaredMemberOf();
            for (Value groupPrincipalName: uniqueMemberOf) {
            // if the user is not a member, add them
            if (!isMemberOf(session, groupPrincipalName.getString(), iGroup)) {
            try {
            // fetch the group
            Iterator authorizableGroups = session.getUserManager().findAuthorizables(PRINCIPAL_NAME, groupPrincipalName.getString());
            if (!authorizableGroups.hasNext()) {
            } else {
            // add the member
            while (authorizableGroups.hasNext()) {
            Group group = (Group) authorizableGroups.next();
            } catch (Exception e) {
            // otherwise skip it
            else {
            LOGGER.debug(“User ” + user.getID() + ” is already a member of ” + groupPrincipalName.getString());
            This code is triggered after the user node is created (/home/users/username) and all of the user attributes are stored under /home/users/username/profile node.
            Node /home/users/username/profile contains an attribute “uniqueMemberOf” – which is nothing but group names to which user belongs in LDAP.
            The above code reads “uniqueMemberOf” attribute (group names) and then adds the user to these groups in CRX. (Note – these groups are created in CRX manually)

            The same stuff I want achieve in 6.1. I hope I am more clear this time.

  4. Hi Lokesh ,

    Is there any way to disable AEM Internal users login after configuring LDAP .
    I mean AEM should only authenticate LDAP users , It shouldn’t allow to authenticate AEM internal users .


  5. Attractive section of content. I simply stumbled upon your weblog and in accession capital to assert that I get actually enjoyed account your weblog posts. Anyway I’ll be subscribing for your feeds or even I success you get entry to persistently quickly.

  6. I do believe all of the ideas you’ve introduced to your post. They are really convincing and can definitely work. Nonetheless, the posts are too brief for newbies. May you please lengthen them a little from next time? Thanks for the post.

  7. I have read a few just right stuff here. Definitely price bookmarking for revisiting. I wonder how a lot attempt you put to create the sort of magnificent informative web site.

  8. It’s actually a cool and useful piece of information. I’m glad that you just shared this helpful info with us. Please keep us up to date like this. Thank you for sharing.

  9. Nice blog here! Also your web site rather a lot up fast! What web host are you using? Can I get your associate hyperlink to your host? I want my website loaded up as quickly as yours lol

  10. I do believe all the concepts you have offered on your post. They are really convincing and can definitely work. Still, the posts are very quick for starters. May just you please extend them a little from subsequent time? Thanks for the post.

  11. Hello, thanks for this article.

    This is the use case: Client does have an authentication system exposed via SOAP. I have imported the WSDL to generate the Java classes.

    I am following this post in order to integrate this third-party authentication system in AEM 6.1. That is, using a custom Oak Login Module, since I do not want to override the default login form.

    However, I am lost in how to tell AEM to use my Custom Login Module, because I do not know what to specify as value for Identity Provider Name (in http://localhost:4502/system/console/configMgr). Besides this line is not being printed: log.info(“######## Inside Custom External Login Module Login Method #######”);

    Helpx says that in order to test the module, AEM should be configured for LDAP, but, how I configure a SOAP service?

    Or what approach do you suggest in this case? Thanks.

  12. Thanks so much
    I’ve created my Custom External Login following this example and it’s working fine except for one detail: I’m not able to see how to create the .token node below the user authenticated.

    Jackrabbit Oak use a TokenLoginModule by default but there is no FACTORY to create an instance of it like I can do with the LoginModule and LoginModuleFactory.

    I have a post opened in Adobe for more than 1 month and nobody give me a solution. It’s really frustrating.


    I’m guessing that probably I need a mix between ExternalLoginModule and TokenLoginModule defined in https://jackrabbit.apache.org/oak/docs/security/authentication/tokenmanagement.html

    I’ll appreciate your time. Thanks

  13. Hi Lokesh,

    We have a unique architecture for authentication and wanted to take some suggestions/inputs from you.

    Our authentication system isn’t a LDAP or any other DS/standard authentication system, it is a custom one which doesn’t provide a lot of information due to security reasons. There is another application between AEM and this authentication system which validates if the user is authenticated or not and stores a cookie with username in the browser. The credentials are captured within a different URL and a cookie is created if authentication is successful

    The requirement is to read this cookie and create an AEM session and a sync user on AEM. This AEM session will be used for social communities to post forum topics and comments.

    Please do suggest if we should be writing a custom authentication handler along with external login module and customIDP class. Its very confusing what combinations to try for the above use case. A starting pointer as to what classes to use would be really helpful


Leave a Reply

Your email address will not be published. Required fields are marked *