/*
* $Id$
*
* Copyright 2006 University of Dundee. All rights reserved.
* Use is subject to license terms supplied in LICENSE.txt
*/
package ome.services.blitz.fire;
import java.util.ArrayList;
import java.util.List;
import ome.api.IQuery;
import ome.conditions.SecurityViolation;
import ome.conditions.SessionException;
import ome.model.meta.Experimenter;
import ome.services.sessions.SessionManager;
import ome.services.util.Executor;
import ome.system.Principal;
import ome.system.ServiceFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.Session;
import org.springframework.transaction.annotation.Transactional;
import Glacier2._PermissionsVerifierDisp;
import Ice.Current;
import Ice.StringHolder;
/**
* @author Josh Moore, josh.moore at gmx.de
* @since 3.0-RC1
*/
public class PermissionsVerifierI extends _PermissionsVerifierDisp {
private final static Logger log = LoggerFactory
.getLogger(PermissionsVerifierI.class);
private final Ring ring;
private final SessionManager manager;
private final Executor ex;
private final Principal p;
public PermissionsVerifierI(Ring ring, SessionManager manager, Executor ex, String uuid) {
this.ring = ring;
this.manager = manager;
this.ex = ex;
this.p = new Principal(uuid);
}
public boolean checkPermissions(final String userId, final String password,
final StringHolder reason, final Current __current) {
try {
// ticket:2212, ticket:3652
//
// At the very first, check if the userId or password is
// actually a session id, if so we enforce that the userId
// and the password are identical, becauser we have no other
// method of signalling to the SessionManagerI instance that
// the user has not provided a real password
//
// The addition of the userId check was added from an odd
// case in which root added a username equal to the current
// session. This prevents any LDAP lookup etc. from happening,
// but by "giving" the user a session id (passed via the username)
// s/he **will** be able to login **AS ROOT**!
//
Object session = null;
// Local checks are faster.
try {
session = manager.find(password);
} catch (SessionException e) {
// pass
}
if (session == null) {
try {
session = manager.find(userId); // ticket:3652
} catch (SessionException e) {
// pass
}
}
// If that doesn't work, make sure that the cluster doesn't know
// something this instance doesn't. (Default of nullRedirector
// returns null immediately)
if (session == null) {
if (ring.checkPassword(userId)) {
session = "ring.checkPassword(userId)";
}
}
/*
* ring.checkPassword calls SqlAction.activeSession
* which logs the user id.
*
if (session == null) {
if (ring.checkPassword(password)) {
session = "ring.checkPassword(password)";
}
}
*/
// If any of the above blocks returned a valid value
// then the password and/or userId matches an active
// session. As long as userId == password, we return
// true. Otherwise we return false, otherwise it
// would be possible to circumvent the @HasPassword
// restrictions.
if (session != null) {
if (userId.equals(password)) {
return true;
} else {
log.warn("username and password don't match: " + userId);
reason.value = "username and password must be equal; use joinSession";
return false;
}
}
// First check locally. Since we typically use redirects in the
// cluster, it's most likely that our password will be in memory
// in this instance.
if (manager.executePasswordCheck(userId, password)) {
return true;
} else {
final List<String> data = new ArrayList<String>();
ex.execute(p, new Executor.SimpleWork("failedPassword", userId) {
@Transactional(readOnly = true)
public Object doWork(Session session, ServiceFactory sf) {
IQuery q = sf.getQueryService();
ome.model.meta.Session s = q.findByString(
ome.model.meta.Session.class, "uuid", userId);
Experimenter e = null;
if (s != null) {
e = s.getOwner();
data.add(String.format("user=%s", e.getOmeName()));
} else {
e = q.findByString(Experimenter.class,
"omeName", userId);
if (e != null) {
data.add(String.format("id=%s", e.getId()));
}
}
if (s != null) {
data.add(String.format("created=%s", s.getStarted()));
data.add(String.format("closed=%s", s.getClosed()));
}
return null;
}
});
reason.value = String.format("Password check failed for '%s': %s",
userId, data);
return false;
}
} catch (SecurityViolation sv) {
reason.value = sv.getMessage();
return false;
} catch (Throwable t) {
reason.value = "Internal error. Please contact your administrator:\n"
+ t.getMessage();
log.error("Exception thrown while checking password for:" + userId,
t);
return false;
}
}
}