07-25-2013 01:10 PM
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
07-26-2013 11:30 AM
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 ...
08-21-2013 12:22 PM
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][1]
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][2] 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 [1]: http://doc.nuxeo.com/display/NXDOC/Adding+custom+LDAP+fields+to+the+UI [2]: https://github.com/nuxeo/nuxeo-services/blob/76ab22f4e9663f62995b9ec09d9612be43e9d460/nuxeo-platform...
Find what you came for
We want to make your experience in Hyland Connect as valuable as possible, so we put together some helpful links.