package org.pac4j.play.java; import org.pac4j.core.config.Config; import org.pac4j.core.context.Pac4jConstants; import org.pac4j.core.context.session.SessionStore; import org.pac4j.core.engine.DefaultSecurityLogic; import org.pac4j.core.engine.SecurityLogic; import org.pac4j.core.exception.TechnicalException; import org.pac4j.core.http.HttpActionAdapter; import org.pac4j.play.PlayWebContext; import org.pac4j.play.store.PlaySessionStore; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import play.mvc.Action; import play.mvc.Http.Context; import play.mvc.Result; import play.libs.concurrent.HttpExecutionContext; import javax.inject.Inject; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import static org.pac4j.core.util.CommonHelper.assertNotNull; /** * <p>This filter protects an url, based on the {@link #securityLogic}.</p> * * <p>The configuration can be provided via annotation parameters: <code>clients</code> (list of clients for authentication), <code>authorizers</code> (list of authorizers) * and <code>multiProfile</code> (whether multiple profiles should be kept).</p> * * @author Jerome Leleu * @author Michael Remond * @since 1.0.0 */ public class SecureAction extends Action<Result> { protected Logger logger = LoggerFactory.getLogger(getClass()); private SecurityLogic<Result, PlayWebContext> securityLogic = new DefaultSecurityLogic<>(); protected final static Method CLIENTS_METHOD; protected final static Method AUTHORIZERS_METHOD; protected final static Method MULTI_PROFILE_METHOD; static { try { CLIENTS_METHOD = Secure.class.getDeclaredMethod(Pac4jConstants.CLIENTS); AUTHORIZERS_METHOD = Secure.class.getDeclaredMethod(Pac4jConstants.AUTHORIZERS); MULTI_PROFILE_METHOD = Secure.class.getDeclaredMethod(Pac4jConstants.MULTI_PROFILE); } catch (final SecurityException | NoSuchMethodException e) { throw new TechnicalException(e); } } final private Config config; final private SessionStore sessionStore; final private HttpExecutionContext ec; @Inject public SecureAction(final Config config, final PlaySessionStore playSessionStore, final HttpExecutionContext ec) { this.config = config; this.config.setSessionStore(playSessionStore); final SecurityLogic configSecurityLogic = config.getSecurityLogic(); if (configSecurityLogic != null) { this.securityLogic = configSecurityLogic; } this.sessionStore = playSessionStore; this.ec = ec; } @Override public CompletionStage<Result> call(final Context ctx) { try{ final InvocationHandler invocationHandler = Proxy.getInvocationHandler(configuration); final String clients = getStringParam(invocationHandler, CLIENTS_METHOD, null); final String authorizers = getStringParam(invocationHandler, AUTHORIZERS_METHOD, null); final boolean multiProfile = getBooleanParam(invocationHandler, MULTI_PROFILE_METHOD, false); return internalCall(ctx, clients, authorizers, multiProfile); }catch(Throwable t){ throw new RuntimeException(t); } } public CompletionStage<Result> internalCall(final Context ctx, final String clients, final String authorizers, final boolean multiProfile) throws Throwable { assertNotNull("securityLogic", securityLogic); assertNotNull("config", config); final PlayWebContext playWebContext = new PlayWebContext(ctx, sessionStore); final HttpActionAdapter actionAdapter = config.getHttpActionAdapter(); return CompletableFuture.supplyAsync(() -> { return securityLogic.perform(playWebContext, config, (webCtx, parameters) -> { // when called from Scala if (delegate == null) { return null; } else { return delegate.call(ctx).toCompletableFuture().get(); } }, actionAdapter, clients, authorizers, null, multiProfile); }, ec.current()); } protected String getStringParam(final InvocationHandler invocationHandler, final Method method, final String defaultValue) throws Throwable { String value = (String) invocationHandler.invoke(configuration, method, null); if (value == null) { value = defaultValue; } logger.debug("String param: {}: {}", method.getName(), value); return value; } protected boolean getBooleanParam(final InvocationHandler invocationHandler, final Method method, final boolean defaultValue) throws Throwable { Boolean value = (Boolean) invocationHandler.invoke(configuration, method, null); if (value == null) { value = defaultValue; } logger.debug("Boolean param: {}: {}", method.getName(), value); return value; } public SecurityLogic<Result, PlayWebContext> getSecurityLogic() { return securityLogic; } public void setSecurityLogic(SecurityLogic<Result, PlayWebContext> securityLogic) { this.securityLogic = securityLogic; } }