/*
* Copyright 2007 Glencoe Software, Inc. All rights reserved.
* Use is subject to license terms supplied in LICENSE.txt
*/
package ome.security.basic;
import ome.conditions.ApiUsageException;
import ome.conditions.InternalException;
import ome.conditions.SessionTimeoutException;
import ome.logic.HardWiredInterceptor;
import ome.security.MethodSecurity;
import ome.services.sessions.stats.DelegatingStats;
import ome.system.Principal;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Responsible for logging users in and out via the {@link Principal} before and
* after the actual invocation of OMERO methods.
*
* This class is the only {@link HardWiredInterceptor} which is hard-wired by
* default into OMERO classes. This permits simple start-up without the need for
* the ant build, which may replace the hard-wired value with a more extensive
* list of {@link HardWiredInterceptor} instances.
*
* Note: any internal "client" will have to handle logging in and out with an
* appropriate {@link Principal}.
*
* @author Josh Moore, josh at glencoesoftware.com
* @since 3.0-Beta2
*/
public final class BasicSecurityWiring extends HardWiredInterceptor {
private final static Logger log = LoggerFactory.getLogger(BasicSecurityWiring.class);
protected PrincipalHolder principalHolder;
protected MethodSecurity methodSecurity;
/**
* Lookup name.
*/
// TODO This should be replaced by a components concept
@Override
public String getName() {
return "securityWiring";
}
/**
* Setter injection.
*/
public void setPrincipalHolder(PrincipalHolder principalHolder) {
this.principalHolder = principalHolder;
}
/**
* Setter injection.
*/
public void setMethodSecurity(MethodSecurity security) {
this.methodSecurity = security;
}
/**
* Wraps all OMERO invocations with login/logout semantics.
*/
public Object invoke(MethodInvocation mi) throws Throwable {
Principal p = getPrincipal(mi);
boolean hp = hasPassword(mi);
boolean close = "close".equals(mi.getMethod().getName());
if (!close && methodSecurity.isActive()) {
methodSecurity.checkMethod(mi.getThis(), mi.getMethod(), p, hp);
}
// First try a login
try {
login(mi, p);
} catch (SessionTimeoutException ste) {
if (!close) {
throw ste;
}
log.warn("SessionTimeoutException on close:" + p);
principalHolder.login(new CloseOnNoSessionContext());
}
// Assuming the above block didn't throw an
// exception, then continue and cleanup.
try {
return mi.proceed();
} finally {
logout();
}
}
private void login(MethodInvocation mi, Principal p) {
if (p == null) {
throw new ApiUsageException(
"ome.system.Principal instance must be provided on login.");
}
int size = principalHolder.size();
if (size > 0) {
throw new InternalException(
"SecuritySystem is still active on login. " + size
+ " logins remaining in thread.");
}
principalHolder.login(p);
if (log.isDebugEnabled()) {
log.debug("Running with user: " + p.getName());
}
}
private void logout() {
int size = principalHolder.logout();
if (size > 0) {
log.error("SecuritySystem is still active on logout. " + size
+ " logins remaining in thread.");
}
}
public static class CloseOnNoSessionContext extends BasicEventContext {
public CloseOnNoSessionContext()
{
super(new Principal(""), new DelegatingStats());
}
}
}