How to allow authentication with readable username instead of uid using LDAP and httpAutomationClient ?

Hello,

We are using a LDAP directory to authenticate users on the nuxeo platform.

With nuxeo drive, users need to authenticate across the platform using their uid as this is the field mapped to the username field of nuxeo user schema.

For authentication across the UI this is not a problem as we're using CAS SSO, but i want my users to be able to use nuxeo drive without knowing their ldap uid.

So … Here is what i tried:

1 / Map readable username stored in ldap to a field in user schema called hrUsername

2/ Rewrite the basic authenticator as following:

   if given login is made from digits (uid), then return it adhoc

   else get it from the hrUsername in directory and return the uid

   initialize UserIdentificationInfo with user uid anyway

3/ Override the AUTOMATION_BASIC_AUTH with my custom class instead of the default one

It does not work though i can see my custom authenticator is used in server.log (and the username to uid part is working)

I noticed that BASIC_AUTH plugin and ANONYMOUS_AUTH plugin are used. I use a specific chain for the */automation pattern where there is no anonymous nor basic auth.

Can someone please give help ? Do I need to write a dedicated LoginPlugin class ? I thought just adapting the UserIdentificationInfo object would be enough …

Thank you,

Antoine

0 votes

1 answers

1058 views

ANSWER

Well, the "connect on automation service using a readable username instead of uid" works, but the token generation and binding of documents does not seem to follow. I've changed the implentation of TokenAuthenticationService to make the username consistent but for now I see very little change …
07/26/2013



It works!

Token acquisition was failing because of our authentication plugin chaining configuration, with CAS AUTH plugin filtering requests sent using TokenAuthenticationServlet pattern instead of letting custom AUTOMATION BASIC AUTH handle this part of the process too.

To sum it up:

1/ Mapping readable username stored in ldap to a field in user schema called hrUsername following help given here

Method to achieve username translation:

public static String uidFromLogin(String login) throws DirectoryException{
            String username; // output string

            // if given login is made from digits, then return
            Pattern pattern = Pattern.compile("^[0-9]*$");
            Matcher matcher = pattern.matcher(login);

            if(matcher.matches()){
                logger.debug(login + " authenticating");
                return login;
            }

            // else transform
            logger.debug("Getting uid from human readable login");
            DirectoryService directoryService=null;
            Directory  directory = null;
            try {
                directoryService = Framework.getService(DirectoryService.class); // get directory service
            } catch (Exception e) {
                logger.error("Failed to get " + DirectoryService.class.getSimpleName() + " service");
            }
            try {
                directory = directoryService.getDirectory("userDirectory"); // get user directory
            } catch (DirectoryException e) {
                logger.error(e.getMessage());
            }
            Session directorySession = null;
            try {
                directorySession = directory.getSession();
            } catch (DirectoryException e2) {
                e2.printStackTrace();
            }


            Map<String, Serializable> filter = new HashMap<String, Serializable>(); // query filter ...
            filter.put("hrUsername", login); // ...will filter user human readable username


            List<String> directoryResults = null;

            try {
                directoryResults = directorySession.getProjection(filter, "username");
            } catch (DirectoryException e) {
                logger.error(e.getMessage());
            } catch (ClientException e) {
                logger.error(e.getMessage());
            } 


            if(directoryResults.size()==1){
                username = directoryResults.get(0);
            }else{
                throw new DirectoryException("User result has to be unique");
            }

            logger.debug(String.format("Returning %s from %s", username, login));

            return username;
        }

2/ Creating a new java class matching exactly default basic authenticator and using previous method to adapt user username

public UserIdentificationInfo handleRetrieveIdentity(
            HttpServletRequest httpRequest, HttpServletResponse httpResponse) {

        logger.debug(BasicDriveAuthenticator.class.getSimpleName()+" : UserIdentificationInfo");
        logger.debug(httpRequest.getHeader("authorization"));
        String auth = httpRequest.getHeader("authorization");

        if (auth != null && auth.toLowerCase().startsWith("basic")) {
            int idx = auth.indexOf(' ');
            String b64userpassword = auth.substring(idx + 1);
            BASE64Decoder decoder = new BASE64Decoder();
            try {
                byte[] clearUp = decoder.decodeBuffer(b64userpassword);
                String userpassword = new String(clearUp);

                logger.debug("Array has size : " + userpassword.split(":").length);

                String username = userpassword.split(":")[0];
                String password = userpassword.split(":")[1];

                username = Ul2AuthenticationUtils.uidFromLogin(username);// <- here


                return new UserIdentificationInfo(username, password); 

            } catch (IOException e) {

                e.printStackTrace();
            } catch (DirectoryException e) {

                e.printStackTrace();
            }
        }
        return null;
    }

3/ Binding this class to AUTOMATION BASIC AUTH authentication plugin

<component name="fr.univlille2.ecm.custom.drive.authenticator">
    <require>org.nuxeo.ecm.platform.ui.web.auth.defaultConfig</require>
    <require>org.nuxeo.ecm.platform.usermanager.UserManagerImpl</require>
    <require>org.nuxeo.ecm.automation.server.auth.config</require>

    <extension
        target="org.nuxeo.ecm.platform.ui.web.auth.service.PluggableAuthenticationService"
        point="authenticators">
        <authenticationPlugin name="AUTOMATION_BASIC_AUTH"
            enabled="true" class="fr.univlille2.ecm.drive.BasicDriveAuthenticator">

        </authenticationPlugin>
    </extension>

</component>

hope this helps

0 votes