blob: 79bf92a374f5e2c455c2f5d41c96ea085edcf8c1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.jsecurity.web;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jsecurity.codec.Base64;
import org.jsecurity.subject.AbstractRememberMeManager;
import org.jsecurity.web.attr.CookieAttribute;
import org.jsecurity.web.attr.WebAttribute;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* Remembers a Subject's identity by using a {@link WebAttribute WebAttribute} instance to retain
* the identity value between web requests.
*
* <p>This class's default <code>WebAttribute</code> instance is a {@link CookieAttribute CookieAttribute}, storing
* the Subject's {@link org.jsecurity.subject.Subject#getPrincipals principals} in a <code>Cookie</code>. Note that
* because this class subclasses the <code>AbstractRememberMeManager</code> which already provides serialization and
* encryption logic, this class utilizes both for added security before setting the cookie value.</p>
*
* <p>This class also contains &quot;passthrough&quot; JavaBeans-compatible getters/setters for the underlying
* <code>CookieAttribute</code>'s properties to make configuration easier.</p>
*
* <p>Note however as a basic sanity check, these passthrough methods will first assert that the underlying
* {@link #getIdentityAttribute identityAttribute} is actually a {@link CookieAttribute CookieAttribute}. If it
* is not, an {@link IllegalStateException} will be thrown. Because the default instance of this class <em>is</em>
* already <code>CookieAttribute</code>, you would only ever experience the exception if you explicitly
* override the internal instance with a different type and accidentally call one of these JavaBeans passthrough
* methods.</p>
*
* <p>Just be aware of this if you manually override the {@link #getIdentityAttribute identityAttribute} property
* to be an instance of something <em>other</em> than a <code>CookieAttribute</code>.</p>
*
* @author Les Hazlewood
* @since 0.9
*/
public class WebRememberMeManager extends AbstractRememberMeManager {
/**
* The default name of the underlying rememberMe cookie which is <code>rememberMe</code>.
*/
public static final String DEFAULT_REMEMBER_ME_COOKIE_NAME = "rememberMe";
private static final Log log = LogFactory.getLog(WebRememberMeManager.class);
protected WebAttribute<String> identityAttribute = null;
public WebRememberMeManager() {
CookieAttribute<String> attr = new CookieAttribute<String>(DEFAULT_REMEMBER_ME_COOKIE_NAME);
attr.setCheckRequestParams(false);
//Peter (JSecurity developer) said that Jetty didn't like the CookieAttribute.INDEFINITE value
// (Tomcat was ok with it), so just default to a few years for now. If anyone doesn't visit a site in 3 years
// after last login, I doubt any JSecurity users would mind their end-users to be forced to log in. - LAH.
attr.setMaxAge(CookieAttribute.ONE_YEAR * 3);
this.identityAttribute = attr;
}
public WebAttribute<String> getIdentityAttribute() {
return identityAttribute;
}
public void setIdentityAttribute(WebAttribute<String> identityAttribute) {
this.identityAttribute = identityAttribute;
}
protected void assertCookieAttribute() {
if (!(this.identityAttribute instanceof CookieAttribute)) {
String msg = "Attempting to access a Cookie property, but the underlying " +
WebAttribute.class.getName() + " instance is not a " +
CookieAttribute.class.getName() + " instance. This is expected if you " +
"are accessing or modifying a cookie property.";
throw new IllegalStateException(msg);
}
}
/**
* Passthrough JavaBeans property that will get the underyling rememberMe cookie's name.
*
* <p>The default value is {@link #DEFAULT_REMEMBER_ME_COOKIE_NAME}</p>
*
* <p>This method performs a quick <code>CookieAttribute</code> sanity check as described in the class-level JavaDoc.</p>
*
* @return the underlying rememberMe cookie's name
*/
public String getCookieName() {
assertCookieAttribute();
return ((CookieAttribute) this.identityAttribute).getName();
}
/**
* Passthrough JavaBeans property that will set the underyling rememberMe cookie's name.
*
* <p>The default value is {@link #DEFAULT_REMEMBER_ME_COOKIE_NAME}</p>
*
* <p>This method performs a quick <code>CookieAttribute</code> sanity check as described in the class-level JavaDoc.</p>
*
* @param name the name to assign to the underlying rememberMe cookie
*/
public void setCookieName(String name) {
assertCookieAttribute();
((CookieAttribute) this.identityAttribute).setName(name);
}
/**
* Passthrough JavaBeans property that will get the underyling rememberMe cookie's path.
*
* <p>This method performs a quick <code>CookieAttribute</code> sanity check as described in the class-level JavaDoc.</p>
*
* @return the underlying rememberMe cookie's path
*/
public String getCookiePath() {
assertCookieAttribute();
return ((CookieAttribute) this.identityAttribute).getPath();
}
/**
* Passthrough JavaBeans property that will set the underyling rememberMe cookie's path.
*
* <p>This method performs a quick <code>CookieAttribute</code> sanity check as described in the class-level JavaDoc.</p>
*
* @param path the path to assign to the underlying rememberMe cookie
*/
public void setCookiePath(String path) {
assertCookieAttribute();
((CookieAttribute) this.identityAttribute).setPath(path);
}
/**
* Passthrough JavaBeans property that will get the underyling rememberMe cookie's max age.
*
* <p>This method performs a quick <code>CookieAttribute</code> sanity check as described in the class-level JavaDoc.</p>
*
* @return the underlying rememberMe cookie's max age.
*/
public int getCookieMaxAge() {
assertCookieAttribute();
return ((CookieAttribute) this.identityAttribute).getMaxAge();
}
/**
* Passthrough JavaBeans property that will get the underyling rememberMe cookie's max age.
*
* <p>This method performs a quick <code>CookieAttribute</code> sanity check as described in the class-level JavaDoc.</p>
*
* @param maxAge the max age to assign to the underlying rememberMe cookie
*/
public void setCookieMaxAge(int maxAge) {
assertCookieAttribute();
((CookieAttribute) this.identityAttribute).setMaxAge(maxAge);
}
/**
* Passthrough JavaBeans property that will get the underyling rememberMe cookie's 'secure' status.
*
* <p>This method performs a quick <code>CookieAttribute</code> sanity check as described in the class-level JavaDoc.</p>
*
* @return the underlying rememberMe cookie's 'secure' flag
*/
public boolean isCookieSecure() {
assertCookieAttribute();
return ((CookieAttribute) this.identityAttribute).isSecure();
}
/**
* Passthrough JavaBeans property that will set the underyling rememberMe cookie's 'secure' status.
*
* <p>This method performs a quick <code>CookieAttribute</code> sanity check as described in the class-level JavaDoc.</p>
*
* @param secure the 'secure' flag to assign to the underlying rememberMe cookie.
*/
public void setCookieSecure(boolean secure) {
assertCookieAttribute();
((CookieAttribute) this.identityAttribute).setSecure(secure);
}
protected void rememberSerializedIdentity(byte[] serialized) {
ServletRequest request = WebUtils.getRequiredServletRequest();
ServletResponse response = WebUtils.getRequiredServletResponse();
//base 64 encode it and store as a cookie:
String base64 = Base64.encodeToString(serialized);
getIdentityAttribute().storeValue(base64, request, response);
}
protected byte[] getSerializedRememberedIdentity() {
ServletRequest request = WebUtils.getRequiredServletRequest();
ServletResponse response = WebUtils.getRequiredServletResponse();
String base64 = getIdentityAttribute().retrieveValue(request, response);
if (base64 != null) {
return Base64.decode(base64);
} else {
//no cookie set - new site visitor?
return null;
}
}
protected void forgetIdentity() {
ServletRequest request = WebUtils.getRequiredServletRequest();
ServletResponse response = WebUtils.getRequiredServletResponse();
getIdentityAttribute().removeValue(request, response);
}
}