/*
* $Id$
*
* Copyright 2009-2011 Glencoe Software, Inc. All rights reserved.
* Use is subject to license terms supplied in LICENSE.txt
*/
package ome.security.auth.providers;
import java.security.Permissions;
import ome.conditions.ApiUsageException;
import ome.logic.LdapImpl;
import ome.model.meta.Experimenter;
import ome.security.SecuritySystem;
import ome.security.auth.ConfigurablePasswordProvider;
import ome.security.auth.PasswordProvider;
import ome.security.auth.PasswordUtil;
import org.springframework.util.Assert;
/**
* LDAP {@link PasswordProvider} which can create users on
* {@link #checkPassword(String, String, boolean) request} to synchronize with an LDAP
* directory. Assuming that a user exists in the configured LDAP store but not
* in the database, then a new user will be created. Authentication, however,
* always takes place against LDAP, and changing passwords is not allowed.
*
* Note: deleted LDAP users will not be removed from OMERO, but will not be able
* to login.
*
* Note: unlike {@link ome.security.auth.LdapPasswordProvider}, this implementation
* (the default LDAP password provider up until 4.3.2) does <em>not</em> check
* the user_filter on every login, but only when a user does not exist. This means
* that when using this implementation it is not possible to remove a user's login
* simply by modifying a part of the user_filter. To workaround various issues described
* under tickets #6248 and #6885, it was necessary to retain this logic in 4.3.3.
*
* @author Josh Moore, josh at glencoesoftware.com
* @see SecuritySystem
* @see Permissions
* @since 4.0
*/
public class LdapPasswordProvider431 extends ConfigurablePasswordProvider {
final protected LdapImpl ldapUtil;
public LdapPasswordProvider431(PasswordUtil util, LdapImpl ldap) {
super(util);
Assert.notNull(ldap);
this.ldapUtil = ldap;
}
public LdapPasswordProvider431(PasswordUtil util,
LdapImpl ldap,
boolean ignoreUnknown) {
super(util, ignoreUnknown);
Assert.notNull(ldap);
this.ldapUtil = ldap;
}
/**
* Only returns if the user is already in the database and has a DN value in
* the password table. Note: after a call to
* {@link #checkPassword(String, String,boolean)} with this same user value, this
* method might begin to return {@code true} due to a call to
* {@link LdapImpl#createUser(String, String)}.
*/
@Override
public boolean hasPassword(String user) {
if (ldapUtil.getSetting()) {
Long id = util.userId(user);
if (id != null) {
String dn = ldapUtil.lookupLdapAuthExperimenter(id);
if (dn != null) {
return true;
}
}
}
return false;
}
@Override
public Boolean checkPassword(String user, String password, boolean readOnly) {
if (!ldapUtil.getSetting()) {
return null; // EARLY EXIT!
}
Long id = util.userId(user);
// Unknown user. First try to create.
if (null == id) {
try {
if (readOnly == true) {
throw new IllegalStateException("Cannot create user!");
}
Experimenter experimenter = ldapUtil.createUser(user, password);
// Use default logic if the user creation did not exist,
// because there may be another non-database login mechanism
// which should also be given a chance.
if (experimenter != null) {
loginAttempt(user, true);
return true;
}
} catch (ApiUsageException e) {
log.info(String.format(
"Default choice on create user: %s (%s)", user, e));
}
}
// Known user
else {
try {
String dn = ldapUtil.lookupLdapAuthExperimenter(id);
if (dn != null) {
return loginAttempt(user,
ldapUtil.validatePassword(dn, password));
}
} catch (ApiUsageException e) {
log.warn("Default choice on check ldap password: " + user, e);
}
}
// If anything goes wrong, use the default (configurable) logic.
return super.checkPassword(user, password, readOnly);
}
}