/*
* Copyright 2015 OmniFaces.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.omnifaces.security.jaspic.wrappers;
import static java.util.logging.Level.FINE;
import static javax.security.auth.message.AuthStatus.SUCCESS;
import static org.omnifaces.security.cdi.Beans.getReferenceOrNull;
import static org.omnifaces.security.jaspic.Utils.getSingleParameterFromState;
import static org.omnifaces.security.jaspic.Utils.notNull;
import static org.omnifaces.security.jaspic.factory.OmniServerAuthContext.REMEMBER_ME_SESSION_NAME;
import java.util.Map;
import java.util.logging.Logger;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.message.AuthException;
import javax.security.auth.message.AuthStatus;
import javax.security.auth.message.MessageInfo;
import javax.security.auth.message.MessagePolicy;
import javax.security.auth.message.module.ServerAuthModule;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;
import org.omnifaces.security.jaspic.core.HttpMsgContext;
import org.omnifaces.security.jaspic.core.ServerAuthModuleWrapper;
import org.omnifaces.security.jaspic.request.LoginTokenCookieDAO;
import org.omnifaces.security.jaspic.request.RememberMeSettingCookieDAO;
import org.omnifaces.security.jaspic.user.TokenAuthenticator;
public class RememberMeWrapper extends ServerAuthModuleWrapper {
private static final Logger logger = Logger.getLogger(RememberMeWrapper.class.getName());
private final LoginTokenCookieDAO cookieDAO = new LoginTokenCookieDAO();
private final RememberMeSettingCookieDAO rememberMeSettingCookieDAO = new RememberMeSettingCookieDAO();
private CallbackHandler handler;
private Map<String, String> options;
public RememberMeWrapper(ServerAuthModule serverAuthModule) {
super(serverAuthModule);
}
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, Map options) throws AuthException {
super.initialize(requestPolicy, responsePolicy, handler, options);
this.handler = handler;
this.options = options;
}
@Override
public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) throws AuthException {
HttpMsgContext msgContext = new HttpMsgContext(handler, options, messageInfo, clientSubject);
TokenAuthenticator tokenAuthenticator = getReferenceOrNull(TokenAuthenticator.class);
Cookie cookie = cookieDAO.get(msgContext.getRequest());
// First try to see if we can authenticate via a cookie
if (notNull(tokenAuthenticator, cookie)) {
if (tokenAuthenticator.authenticate(cookie.getValue())) {
// We were able to authenticate via the remember-me cookie, register this with the container and return
msgContext.registerWithContainer(tokenAuthenticator.getUserName(), tokenAuthenticator.getApplicationRoles());
return SUCCESS; // return SUCCESS just as a SAM would
} else {
// Invalid cookie, remove it
cookieDAO.remove(msgContext.getRequest(), msgContext.getResponse());
}
}
// Let the next wrapper of SAM try to authenticate
AuthStatus authstatus = super.validateRequest(messageInfo, clientSubject, serviceSubject);
if (tokenAuthenticator != null && authstatus == SUCCESS && tokenAuthenticator.getUserName() != null && isRememberMe(msgContext)) {
cookieDAO.save(msgContext.getRequest(), msgContext.getResponse(), tokenAuthenticator.generateLoginToken());
}
return authstatus;
}
@Override
public void cleanSubject(MessageInfo messageInfo, Subject subject) throws AuthException {
HttpMsgContext msgContext = new HttpMsgContext(handler, options, messageInfo, subject);
// If there's a "remember me" cookie present, remove it.
Cookie cookie = cookieDAO.get(msgContext.getRequest());
if (cookie != null) {
cookieDAO.remove(msgContext.getRequest(), msgContext.getResponse());
TokenAuthenticator tokenAuthenticator = getReferenceOrNull(TokenAuthenticator.class);
if (tokenAuthenticator != null) {
tokenAuthenticator.removeLoginToken(cookie.getValue());
}
}
super.cleanSubject(messageInfo, subject);
}
public boolean isRememberMe(HttpMsgContext msgContext) {
// TODO: handle state better
if (msgContext.getAuthParameters().getRememberMe() != null) {
return msgContext.getAuthParameters().getRememberMe();
}
if (msgContext.getRequest().getParameter("state") != null) {
try {
String rememberMe = getSingleParameterFromState(msgContext.getRequest().getParameter("state"), "rememberMe");
if (rememberMe != null) {
return Boolean.valueOf(rememberMe);
}
}
catch (IllegalArgumentException e) {
logger.log(FINE, "Unable to decode state parameter", e);
}
}
Cookie rememberMeSettingCookie = rememberMeSettingCookieDAO.get(msgContext.getRequest());
if (rememberMeSettingCookie != null) {
try {
return Boolean.valueOf(rememberMeSettingCookie.getValue());
}
finally {
rememberMeSettingCookieDAO.remove(msgContext.getRequest(), msgContext.getResponse());
}
}
HttpSession session = msgContext.getRequest().getSession(false);
if (session != null) {
Boolean rememberMe = (Boolean) session.getAttribute(REMEMBER_ME_SESSION_NAME);
if (rememberMe != null) {
return rememberMe;
}
}
return false;
}
}