Hello, based on your example from the forums I’ve created a custom PAM authenticator; it will first check if there are reportserver credentials available and if not it will try to look up the user using ldap (active directory).
So far, so good; the authenticator returns an AuthenticationResult, but the user is still not allowed to login.
The user entity is not imported, it’s simply created manually. Am I missing something? Is there a requirement for setting origin or credentials or something?
package ldap
import javax.naming.AuthenticationException
import javax.naming.Context
import javax.naming.InvalidNameException
import javax.naming.NamingException
import javax.naming.directory.InitialDirContext
import javax.persistence.NoResultException
import net.datenwerke.rs.authenticator.client.login.dto.UserPasswordAuthToken
import net.datenwerke.rs.authenticator.client.login.pam.UserPasswordClientPAM
import net.datenwerke.rs.utils.crypto.PasswordHasher;
import net.datenwerke.security.client.login.AuthToken
import net.datenwerke.security.service.authenticator.AuthenticationResult
import net.datenwerke.security.service.authenticator.ReportServerPAM
import net.datenwerke.security.service.authenticator.hooks.PAMHook
import net.datenwerke.security.service.usermanager.UserManagerService
import net.datenwerke.security.service.usermanager.entities.User
import com.google.inject.Inject
final LdapPAM ldapPam = GLOBALS.injector.getInstance(LdapPAM.class);
GLOBALS.services.callbackRegistry.attachHook("LDAP_PAM", PAMHook.class, new PAMHook(){
public void beforeStaticPamConfig(LinkedHashSet<ReportServerPAM> pams){
pams.add(ldapPam);
}
public void afterStaticPamConfig(LinkedHashSet<ReportServerPAM> pams){
}
});
public class LdapPAM implements ReportServerPAM {
private static final String CLIENT_MODULE_NAME = UserPasswordClientPAM.class.getName();
UserManagerService userManagerService;
PasswordHasher passwordHasher;
@Inject
public UserPasswordPAM(UserManagerService userManagerService,PasswordHasher passwordHasher) {
this.userManagerService = userManagerService;
this.passwordHasher = passwordHasher;
}
public AuthenticationResult authenticate(AuthToken[] tokens) {
for(Object token : tokens){
if(token instanceof UserPasswordAuthToken){
UserPasswordAuthToken credentials = (UserPasswordAuthToken) token;
/* First try reportserver internal authentication */
User u = authenticateInternal(credentials.getUsername(), credentials.getPassword());
if(null != u){
return new AuthenticationResult(true, u, true);
}else{
/* Secondly try LDAP authentication */
u = authenticate(credentials.getUsername(), credentials.getPassword());
if(null != u){
return new AuthenticationResult(true, u, true);
}
else{
User usr = getUserOrNull(credentials.getUsername());
return new AuthenticationResult(false, usr, true);
}
}
}
}
return new AuthenticationResult(false, null, false);
}
protected User getUserOrNull(String username){
try{
return userManagerService.getUserByName(username);
}catch(NoResultException ex){
return null;
}
}
public User authenticateInternal(String username, String cleartextPassword){
if(cleartextPassword==null || cleartextPassword.empty) return null;
User user = getUserOrNull(username);
if(null == user)
return null;
if(null != user.getPassword() && passwordHasher.validatePassword(user.getPassword(), cleartextPassword)){
return user;
}else
return null;
}
public User authenticate(String username, String cleartextPassword){
User user = getUserOrNull(username);
if(null == user)
return null;
LdapAuthenticator authenticator = new LdapAuthenticator();
if(authenticator.authenticate(user, cleartextPassword)){
return user;
}else{
return null;
}
}
public String getClientModuleName() {
return CLIENT_MODULE_NAME;
}
}
public class LdapAuthenticator {
/* The active directory domain */
String domainName = "mydomain.local";
/* The provider server */
String server = "server-dc";
public boolean authenticate(User user, String password){
if(password==null || password.empty) return false
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
props.setProperty(Context.PROVIDER_URL, "ldap://${server}.${domainName}/");
props.setProperty(Context.URL_PKG_PREFIXES, "com.sun.jndi.url");
props.setProperty(Context.SECURITY_AUTHENTICATION, "simple");
props.setProperty(Context.SECURITY_PRINCIPAL, "${user.username}@${domainName}");
props.setProperty(Context.SECURITY_CREDENTIALS, password);
try {
InitialDirContext ctx = new InitialDirContext(props);
return true;
} catch (AuthenticationException e) {
return false;
} catch (InvalidNameException e) {
throw new RuntimeException(e);
} catch (NamingException e) {
if(e.getMessage().contains("LdapErr: DSID-0C0906E8")){
return false;
}
}
}
}