1
0
mirror of synced 2026-08-05 01:36:56 +00:00

Initial CAS support.

This commit is contained in:
Ben Alex
2004-04-19 07:34:32 +00:00
parent 782bfe5a74
commit fa9b872570
60 changed files with 5561 additions and 17 deletions
@@ -0,0 +1,220 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.BadCredentialsException;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.providers.AuthenticationProvider;
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import net.sf.acegisecurity.ui.cas.CasProcessingFilter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
/**
* An {@link AuthenticationProvider} implementation that integrates with Yale
* Central Authentication Service (CAS).
*
* <p>
* This <code>AuthenticationProvider</code> is capable of validating {@link
* UsernamePasswordAuthenticationToken} requests which contain a
* <code>principal</code> name equal to either {@link
* CasProcessingFilter#CAS_STATEFUL_IDENTIFIER} or {@link
* CasProcessingFilter#CAS_STATELESS_IDENTIFIER}. It can also validate a
* previously created {@link CasAuthenticationToken}.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class CasAuthenticationProvider implements AuthenticationProvider,
InitializingBean {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(CasAuthenticationProvider.class);
//~ Instance fields ========================================================
private CasAuthoritiesPopulator casAuthoritiesPopulator;
private CasProxyDecider casProxyDecider;
private StatelessTicketCache statelessTicketCache;
private String key;
private TicketValidator ticketValidator;
//~ Methods ================================================================
public void setCasAuthoritiesPopulator(
CasAuthoritiesPopulator casAuthoritiesPopulator) {
this.casAuthoritiesPopulator = casAuthoritiesPopulator;
}
public CasAuthoritiesPopulator getCasAuthoritiesPopulator() {
return casAuthoritiesPopulator;
}
public void setCasProxyDecider(CasProxyDecider casProxyDecider) {
this.casProxyDecider = casProxyDecider;
}
public CasProxyDecider getCasProxyDecider() {
return casProxyDecider;
}
public void setKey(String key) {
this.key = key;
}
public String getKey() {
return key;
}
public void setStatelessTicketCache(
StatelessTicketCache statelessTicketCache) {
this.statelessTicketCache = statelessTicketCache;
}
public StatelessTicketCache getStatelessTicketCache() {
return statelessTicketCache;
}
public void setTicketValidator(TicketValidator ticketValidator) {
this.ticketValidator = ticketValidator;
}
public TicketValidator getTicketValidator() {
return ticketValidator;
}
public void afterPropertiesSet() throws Exception {
if (this.casAuthoritiesPopulator == null) {
throw new IllegalArgumentException(
"A casAuthoritiesPopulator must be set");
}
if (this.ticketValidator == null) {
throw new IllegalArgumentException("A ticketValidator must be set");
}
if (this.casProxyDecider == null) {
throw new IllegalArgumentException("A casProxyDecider must be set");
}
if (this.statelessTicketCache == null) {
throw new IllegalArgumentException(
"A statelessTicketCache must be set");
}
if (key == null) {
throw new IllegalArgumentException(
"A Key is required so CasAuthenticationProvider can identify tokens it previously authenticated");
}
}
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
if (!supports(authentication.getClass())) {
return null;
}
if (authentication instanceof UsernamePasswordAuthenticationToken
&& (!CasProcessingFilter.CAS_STATEFUL_IDENTIFIER.equals(
authentication.getPrincipal().toString())
&& !CasProcessingFilter.CAS_STATELESS_IDENTIFIER.equals(
authentication.getPrincipal().toString()))) {
// UsernamePasswordAuthenticationToken not CAS related
return null;
}
// If an existing CasAuthenticationToken, just check we created it
if (authentication instanceof CasAuthenticationToken) {
if (this.key.hashCode() == ((CasAuthenticationToken) authentication)
.getKeyHash()) {
return authentication;
} else {
throw new BadCredentialsException(
"The presented CasAuthenticationToken does not contain the expected key");
}
}
// Ensure credentials are presented
if (authentication.getCredentials() == null || "".equals(authentication.getCredentials())) {
throw new BadCredentialsException(
"Failed to provide a CAS service ticket to validate");
}
boolean stateless = false;
if (authentication instanceof UsernamePasswordAuthenticationToken
&& CasProcessingFilter.CAS_STATELESS_IDENTIFIER.equals(
authentication.getPrincipal())) {
stateless = true;
}
CasAuthenticationToken result = null;
if (stateless) {
// Try to obtain from cache
result = statelessTicketCache.getByTicketId(authentication.getCredentials()
.toString());
}
if (result == null) {
result = this.authenticateNow(authentication);
}
if (stateless) {
// Add to cache
statelessTicketCache.putTicketInCache(result);
}
return result;
}
public boolean supports(Class authentication) {
if (UsernamePasswordAuthenticationToken.class.isAssignableFrom(
authentication)) {
return true;
} else if (CasAuthenticationToken.class.isAssignableFrom(authentication)) {
return true;
} else {
return false;
}
}
private CasAuthenticationToken authenticateNow(
Authentication authentication) throws AuthenticationException {
// Validate
TicketResponse response = ticketValidator.confirmTicketValid(authentication.getCredentials()
.toString());
// Check proxy list is trusted
this.casProxyDecider.confirmProxyListTrusted(response.getProxyList());
// Build list of granted authorities
GrantedAuthority[] ga = this.casAuthoritiesPopulator.getAuthorities(response
.getUser());
// Construct CasAuthenticationToken
return new CasAuthenticationToken(this.key, response.getUser(),
authentication.getCredentials(), ga, response.getProxyList(),
response.getProxyGrantingTicketIou());
}
}
@@ -0,0 +1,172 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.providers.AbstractAuthenticationToken;
import java.io.Serializable;
import java.util.List;
/**
* Represents a successful CAS <code>Authentication</code>.
*
* @author Ben Alex
* @version $Id$
*/
public class CasAuthenticationToken extends AbstractAuthenticationToken implements Serializable {
//~ Instance fields ========================================================
private List proxyList;
private Object credentials;
private Object principal;
private String proxyGrantingTicketIou;
private GrantedAuthority[] authorities;
private int keyHash;
//~ Constructors ===========================================================
/**
* Constructor.
*
* @param key to identify if this object made by a given {@link
* CasAuthenticationProvider}
* @param principal the username from CAS (cannot be <code>null</code>)
* @param credentials the service/proxy ticket ID from CAS (cannot be
* <code>null</code>)
* @param authorities the authorities granted to the user (from {@link
* CasAuthoritiesPopulator}) (cannot be <code>null</code>)
* @param proxyList the list of proxies from CAS (cannot be
* <code>null</code>)
* @param proxyGrantingTicketIou the PGT-IOU ID from CAS (cannot be
* <code>null</code>)
*
* @throws IllegalArgumentException if a <code>null</code> was passed
*/
public CasAuthenticationToken(String key, Object principal,
Object credentials, GrantedAuthority[] authorities, List proxyList,
String proxyGrantingTicketIou) {
if ((key == null) || ("".equals(key)) || (principal == null)
|| "".equals(principal) || (credentials == null)
|| "".equals(credentials) || (authorities == null)
|| (proxyList == null) || (proxyGrantingTicketIou == null)
|| ("".equals(proxyGrantingTicketIou))) {
throw new IllegalArgumentException(
"Cannot pass null or empty values to constructor");
}
for (int i = 0; i < authorities.length; i++) {
if (authorities[i] == null) {
throw new IllegalArgumentException("Granted authority element "
+ i
+ " is null - GrantedAuthority[] cannot contain any null elements");
}
}
this.keyHash = key.hashCode();
this.principal = principal;
this.credentials = credentials;
this.authorities = authorities;
this.proxyList = proxyList;
this.proxyGrantingTicketIou = proxyGrantingTicketIou;
}
protected CasAuthenticationToken() {
throw new IllegalArgumentException("Cannot use default constructor");
}
//~ Methods ================================================================
/**
* Ignored (always <code>true</code>).
*
* @param isAuthenticated ignored
*/
public void setAuthenticated(boolean isAuthenticated) {
// ignored
}
/**
* Always returns <code>true</code>.
*
* @return true
*/
public boolean isAuthenticated() {
return true;
}
public GrantedAuthority[] getAuthorities() {
return this.authorities;
}
public Object getCredentials() {
return this.credentials;
}
public int getKeyHash() {
return this.keyHash;
}
public Object getPrincipal() {
return this.principal;
}
public String getProxyGrantingTicketIou() {
return proxyGrantingTicketIou;
}
public List getProxyList() {
return proxyList;
}
public boolean equals(Object obj) {
if (!super.equals(obj)) {
return false;
}
if (obj instanceof CasAuthenticationToken) {
CasAuthenticationToken test = (CasAuthenticationToken) obj;
// proxyGrantingTicketIou is never null due to constructor
if (!this.getProxyGrantingTicketIou().equals(test
.getProxyGrantingTicketIou())) {
return false;
}
// proxyList is never null due to constructor
if (!this.getProxyList().equals(test.getProxyList())) {
return false;
}
return true;
}
System.out.println("THey're not equal");
return false;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(super.toString());
sb.append("; Credentials (Service/Proxy Ticket): " + this.credentials);
sb.append("; Proxy-Granting Ticket IOU: " + this.proxyGrantingTicketIou);
sb.append("; Proxy List: " + this.proxyList.toString());
return sb.toString();
}
}
@@ -0,0 +1,59 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.GrantedAuthority;
/**
* Populates the <code>GrantedAuthority[]</code> objects for a CAS
* authenticated user.
*
* <P>
* CAS does not provide the authorities (roles) granted to a user. It merely
* authenticates their identity. As the Acegi Security System for Spring needs
* to know the authorities granted to a user in order to construct a valid
* <code>Authentication</code> object, implementations of this interface will
* provide this information.
* </p>
*
* <P>
* Implementations should not perform any caching. They will only be called
* when a refresh is required.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public interface CasAuthoritiesPopulator {
//~ Methods ================================================================
/**
* Obtains the granted authorities for the specified user.
*
* <P>
* May throw any <code>AuthenticationException</code> or return
* <code>null</code> if the authorities are unavailable.
* </p>
*
* @param casUserId as obtained from the CAS validation service
*
* @return the granted authorities for the indicated user
*/
public GrantedAuthority[] getAuthorities(String casUserId)
throws AuthenticationException;
}
@@ -0,0 +1,72 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas;
import java.util.List;
/**
* Decides whether a proxy list presented via CAS is trusted or not.
*
* <P>
* CAS 1.0 allowed services to receive a service ticket and then validate it.
* CAS 2.0 allows services to receive a service ticket and then validate it
* with a proxy callback URL. The callback will enable the CAS server to
* authenticate the service. In doing so the service will receive a
* proxy-granting ticket and a proxy-granting ticket IOU. The IOU is just an
* internal record that a proxy-granting ticket is due to be received via the
* callback URL.
* </p>
*
* <P>
* With a proxy-granting ticket, a service can request the CAS server provides
* it with a proxy ticket. A proxy ticket is just a service ticket, but the
* CAS server internally tracks the list (chain) of services used to build the
* proxy ticket. The proxy ticket is then presented to the target service.
* </p>
*
* <P>
* If this application is a target service of a proxy ticket, the
* <code>CasProxyDecider</code> resolves whether or not the proxy list is
* trusted. Applications should only trust services they allow to impersonate
* an end user.
* </p>
*
* <P>
* If this application is a service that should never accept proxy-granting
* tickets, the implementation should reject tickets that present a proxy list
* with any members. If the list has no members, it indicates the CAS server
* directly authenticated the user (ie there are no services which proxied the
* user authentication).
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public interface CasProxyDecider {
//~ Methods ================================================================
/**
* Decides whether the proxy list is trusted.
*
* <P>
* Must throw any <code>ProxyUntrustedException</code> if the proxy list is
* untrusted.
* </p>
*/
public void confirmProxyListTrusted(List proxyList)
throws ProxyUntrustedException;
}
@@ -0,0 +1,50 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas;
import net.sf.acegisecurity.AuthenticationException;
/**
* Thrown if a CAS proxy ticket is presented from an untrusted proxy.
*
* @author Ben Alex
* @version $Id$
*/
public class ProxyUntrustedException extends AuthenticationException {
//~ Constructors ===========================================================
/**
* Constructs a <code>ProxyUntrustedException</code> with the specified
* message.
*
* @param msg the detail message.
*/
public ProxyUntrustedException(String msg) {
super(msg);
}
/**
* Constructs a <code>ProxyUntrustedException</code> with the specified
* message and root cause.
*
* @param msg the detail message.
* @param t root cause
*/
public ProxyUntrustedException(String msg, Throwable t) {
super(msg, t);
}
}
@@ -0,0 +1,116 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas;
/**
* Caches CAS service tickets and CAS proxy tickets for stateless connections.
*
* <p>
* When a service ticket or proxy ticket is validated against the CAS server,
* it is unable to be used again. Most types of callers are stateful and are
* associated with a given <code>HttpSession</code>. This allows the
* affirmative CAS validation outcome to be stored in the
* <code>HttpSession</code>, meaning the removal of the ticket from the CAS
* server is not an issue issue.
* </p>
*
* <P>
* Stateless callers, such as remoting protocols, cannot take advantage of
* <code>HttpSession</code>. If the stateless caller is located a significant
* network distance from the CAS server, acquiring a fresh service ticket or
* proxy ticket for each invocation would be expensive.
* </p>
*
* <P>
* To avoid this issue with stateless callers, it is expected stateless callers
* will obtain a single service ticket or proxy ticket, and then present this
* same ticket to the Acegi Security System secured application on each
* occasion. As no <code>HttpSession</code> is available for such callers, the
* affirmative CAS validation outcome cannot be stored in this location.
* </p>
*
* <P>
* The <code>StatelessTicketCache</code> enables the service tickets and proxy
* tickets belonging to stateless callers to be placed in a cache. This
* in-memory cache stores the <code>CasAuthenticationToken</code>, effectively
* providing the same capability as a <code>HttpSession</code> with the ticket
* identifier being the key rather than a session identifier.
* </p>
*
* <P>
* Implementations should provide a reasonable timeout on stored entries, such
* that the stateless caller are not required to unnecessarily acquire fresh
* CAS service tickets or proxy tickets.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public interface StatelessTicketCache {
//~ Methods ================================================================
/**
* Retrieves the <code>CasAuthenticationToken</code> associated with the
* specified ticket.
*
* <P>
* If not found, returns a
* <code>null</code><code>CasAuthenticationToken</code>.
* </p>
*
* @return the fully populated authentication token
*/
public CasAuthenticationToken getByTicketId(String serviceTicket);
/**
* Adds the specified <code>CasAuthenticationToken</code> to the cache.
*
* <P>
* The {@link CasAuthenticationToken#getCredentials()} method is used to
* retrieve the service ticket number.
* </p>
*
* @param token to be added to the cache
*/
public void putTicketInCache(CasAuthenticationToken token);
/**
* Removes the specified ticket from the cache, as per {@link
* #removeTicketFromCache(String)}.
*
* <P>
* Implementations should use {@link
* CasAuthenticationToken#getCredentials()} to obtain the ticket and then
* delegate to to the {@link #removeTicketFromCache(String)} method.
* </p>
*
* @param token to be removed
*/
public void removeTicketFromCache(CasAuthenticationToken token);
/**
* Removes the specified ticket from the cache, meaning that future calls
* will require a new service ticket.
*
* <P>
* This is in case applications wish to provide a session termination
* capability for their stateless clients.
* </p>
*
* @param serviceTicket to be removed
*/
public void removeTicketFromCache(String serviceTicket);
}
@@ -0,0 +1,102 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas;
import java.util.List;
import java.util.Vector;
/**
* Represents a CAS service ticket in native CAS form.
*
* @author Ben Alex
* @version $Id$
*/
public class TicketResponse {
//~ Instance fields ========================================================
private List proxyList;
private String proxyGrantingTicketIou;
private String user;
//~ Constructors ===========================================================
/**
* Constructor.
*
* <P>
* If <code>null</code> is passed into the <code>proxyList</code> or
* <code>proxyGrantingTicketIou</code>, suitable defaults are established.
* However, <code>null</code> cannot be passed for the <code>user</code>
* argument.
* </p>
*
* @param user the user as indicated by CAS (cannot be <code>null</code> or
* an empty <code>String</code>)
* @param proxyList as provided by CAS (may be <code>null</code>)
* @param proxyGrantingTicketIou as provided by CAS (may be
* <code>null</code>)
*
* @throws IllegalArgumentException DOCUMENT ME!
*/
public TicketResponse(String user, List proxyList,
String proxyGrantingTicketIou) {
if (proxyList == null) {
proxyList = new Vector();
}
if (proxyGrantingTicketIou == null) {
proxyGrantingTicketIou = "";
}
if ((user == null) || "".equals(user)) {
throw new IllegalArgumentException(
"Cannot pass null or empty String for User");
}
this.user = user;
this.proxyList = proxyList;
this.proxyGrantingTicketIou = proxyGrantingTicketIou;
}
protected TicketResponse() {
throw new IllegalArgumentException("Cannot use default constructor");
}
//~ Methods ================================================================
public String getProxyGrantingTicketIou() {
return proxyGrantingTicketIou;
}
public List getProxyList() {
return proxyList;
}
public String getUser() {
return user;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(super.toString());
sb.append(": User: " + this.user);
sb.append("; Proxy-Granting Ticket IOU: " + this.proxyGrantingTicketIou);
sb.append("; Proxy List: " + this.proxyList.toString());
return sb.toString();
}
}
@@ -0,0 +1,53 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas;
import net.sf.acegisecurity.AuthenticationException;
/**
* Validates a CAS service ticket.
*
* <P>
* Implementations must accept CAS proxy tickets, in addition to CAS service
* tickets. If proxy tickets should be rejected, this is resolved by a {@link
* CasProxyDecider} implementation (not by the <code>TicketValidator</code>).
* </p>
*
* <P>
* Implementations may request a proxy granting ticket if wish, although this
* behaviour is not mandatory.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public interface TicketValidator {
//~ Methods ================================================================
/**
* Returns information about the ticket, if it is valid for this service.
*
* <P>
* Must throw an <code>AuthenticationException</code> if the ticket is not
* valid for this service.
* </p>
*
* @return details of the CAS service ticket
*/
public TicketResponse confirmTicketValid(String serviceTicket)
throws AuthenticationException;
}
@@ -0,0 +1,108 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas.cache;
import net.sf.acegisecurity.providers.cas.CasAuthenticationToken;
import net.sf.acegisecurity.providers.cas.StatelessTicketCache;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataRetrievalFailureException;
/**
* Caches tickets using <A HREF="http://ehcache.sourceforge.net">EHCACHE</a>.
*
* @author Ben Alex
* @version $Id$
*/
public class EhCacheBasedTicketCache implements StatelessTicketCache,
InitializingBean {
//~ Instance fields ========================================================
private Cache cache;
private CacheManager manager;
private int minutesToIdle = 20;
//~ Methods ================================================================
public CasAuthenticationToken getByTicketId(String serviceTicket) {
Element element = null;
try {
element = cache.get(serviceTicket);
} catch (CacheException cacheException) {
throw new DataRetrievalFailureException("Cache failure: "
+ cacheException.getMessage());
}
if (element == null) {
System.out.println("not found");
return null;
} else {
System.out.println("found");
return (CasAuthenticationToken) element.getValue();
}
}
public void setMinutesToIdle(int minutesToIdle) {
this.minutesToIdle = minutesToIdle;
}
/**
* Specifies how many minutes an entry will remain in the cache from when
* it was last accessed. This is effectively the session duration.
*
* <P>
* Defaults to 20 minutes.
* </p>
*
* @return Returns the minutes an element remains in the cache
*/
public int getMinutesToIdle() {
return minutesToIdle;
}
public void afterPropertiesSet() throws Exception {
manager = CacheManager.create();
// Cache name, max memory, overflowToDisk, eternal, timeToLive, timeToIdle
cache = new Cache("ehCacheBasedTicketCache", Integer.MAX_VALUE, false,
false, minutesToIdle * 60, minutesToIdle * 60);
manager.addCache(cache);
}
public void putTicketInCache(CasAuthenticationToken token) {
Element element = new Element(token.getCredentials().toString(), token);
System.out.println("Adding " + element.getKey());
cache.put(element);
}
public void removeTicketFromCache(CasAuthenticationToken token) {
this.removeTicketFromCache(token.getCredentials().toString());
}
public void removeTicketFromCache(String serviceTicket) {
cache.remove(serviceTicket);
}
}
@@ -0,0 +1,6 @@
<html>
<body>
An authentication provider that can process Yale Central Authentication Service (CAS)
service tickets and proxy tickets.
</body>
</html>
@@ -0,0 +1,67 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas.populator;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.providers.cas.CasAuthoritiesPopulator;
import net.sf.acegisecurity.providers.dao.AuthenticationDao;
import org.springframework.beans.factory.InitializingBean;
/**
* Populates the CAS authorities via an {@link AuthenticationDao}.
*
* <P>
* The additional information (username, password, enabled status etc) an
* <code>AuthenticationDao</code> implementation provides about a
* <code>User</code> is ignored. Only the <code>GrantedAuthority</code>s are
* relevant to this class.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class DaoCasAuthoritiesPopulator implements CasAuthoritiesPopulator,
InitializingBean {
//~ Instance fields ========================================================
private AuthenticationDao authenticationDao;
//~ Methods ================================================================
public void setAuthenticationDao(AuthenticationDao authenticationDao) {
this.authenticationDao = authenticationDao;
}
public AuthenticationDao getAuthenticationDao() {
return authenticationDao;
}
public GrantedAuthority[] getAuthorities(String casUserId)
throws AuthenticationException {
return this.authenticationDao.loadUserByUsername(casUserId)
.getAuthorities();
}
public void afterPropertiesSet() throws Exception {
if (this.authenticationDao == null) {
throw new IllegalArgumentException(
"An authenticationDao must be set");
}
}
}
@@ -0,0 +1,5 @@
<html>
<body>
Implementations that populate GrantedAuthority[]s of CAS authentications.
</body>
</html>
@@ -0,0 +1,55 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas.proxy;
import net.sf.acegisecurity.providers.cas.CasProxyDecider;
import net.sf.acegisecurity.providers.cas.ProxyUntrustedException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.List;
/**
* Accepts a proxied request from any other service.
*
* <P>
* Also accepts the request if there was no proxy (ie the user directly
* authenticated against this service).
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class AcceptAnyCasProxy implements CasProxyDecider {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(AcceptAnyCasProxy.class);
//~ Methods ================================================================
public void confirmProxyListTrusted(List proxyList)
throws ProxyUntrustedException {
if (proxyList == null) {
throw new IllegalArgumentException("proxyList cannot be null");
}
if (logger.isDebugEnabled()) {
logger.debug("Always accepting proxy list: " + proxyList.toString());
}
}
}
@@ -0,0 +1,87 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas.proxy;
import net.sf.acegisecurity.providers.cas.CasProxyDecider;
import net.sf.acegisecurity.providers.cas.ProxyUntrustedException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import java.util.List;
/**
* Accepts proxied requests if the closest proxy is named in the
* <code>validProxies</code> list.
*
* <P>
* Also accepts the request if there was no proxy (ie the user directly
* authenticated against this service).
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class NamedCasProxyDecider implements CasProxyDecider, InitializingBean {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(NamedCasProxyDecider.class);
//~ Instance fields ========================================================
private List validProxies;
//~ Methods ================================================================
public void setValidProxies(List validProxies) {
this.validProxies = validProxies;
}
public List getValidProxies() {
return validProxies;
}
public void afterPropertiesSet() throws Exception {
if (this.validProxies == null) {
throw new IllegalArgumentException(
"A validProxies list must be set");
}
}
public void confirmProxyListTrusted(List proxyList)
throws ProxyUntrustedException {
if (proxyList == null) {
throw new IllegalArgumentException("proxyList cannot be null");
}
if (logger.isDebugEnabled()) {
logger.debug("Proxy list: " + proxyList.toString());
}
if (proxyList.size() == 0) {
// A Service Ticket (not a Proxy Ticket)
return;
}
if (!validProxies.contains(proxyList.get(0))) {
throw new ProxyUntrustedException("Nearest proxy '"
+ proxyList.get(0) + "' is untrusted");
}
}
}
@@ -0,0 +1,63 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas.proxy;
import net.sf.acegisecurity.providers.cas.CasProxyDecider;
import net.sf.acegisecurity.providers.cas.ProxyUntrustedException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.List;
/**
* Accepts no proxied requests.
*
* <P>
* This class should be used if only service tickets wish to be accepted (ie no
* proxy tickets at all).
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class RejectProxyTickets implements CasProxyDecider {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(RejectProxyTickets.class);
//~ Methods ================================================================
public void confirmProxyListTrusted(List proxyList)
throws ProxyUntrustedException {
if (proxyList == null) {
throw new IllegalArgumentException("proxyList cannot be null");
}
if (proxyList.size() == 0) {
// A Service Ticket (not a Proxy Ticket)
return;
}
if (logger.isDebugEnabled()) {
logger.debug("Proxies are unacceptable; proxy list provided: "
+ proxyList.toString());
}
throw new ProxyUntrustedException("Proxy tickets are rejected");
}
}
@@ -0,0 +1,6 @@
<html>
<body>
Implementations that decide whether proxy lists of
CAS authentications are trusted.
</body>
</html>
@@ -0,0 +1,96 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas.ticketvalidator;
import net.sf.acegisecurity.providers.cas.TicketValidator;
import net.sf.acegisecurity.ui.cas.ServiceProperties;
import org.springframework.beans.factory.InitializingBean;
/**
* Convenience abstract base for <code>TicketValidator</code>s.
*
* @author Ben Alex
* @version $Id$
*/
public abstract class AbstractTicketValidator implements TicketValidator,
InitializingBean {
//~ Instance fields ========================================================
private ServiceProperties serviceProperties;
private String casValidate;
private String trustStore;
//~ Methods ================================================================
public void setCasValidate(String casValidate) {
this.casValidate = casValidate;
}
/**
* Mandatory URL to CAS' proxy ticket valiation service.
*
* <P>
* This is usually something like
* <code>https://www.mycompany.com/cas/proxyValidate</code>.
* </p>
*
* @return the CAS proxy ticket validation URL
*/
public String getCasValidate() {
return casValidate;
}
public void setServiceProperties(ServiceProperties serviceProperties) {
this.serviceProperties = serviceProperties;
}
public ServiceProperties getServiceProperties() {
return serviceProperties;
}
public void setTrustStore(String trustStore) {
this.trustStore = trustStore;
}
/**
* Optional property which will be used to set the system property
* <code>javax.net.ssl.trustStore</code>.
*
* @return the <code>javax.net.ssl.trustStore</code> that will be set
* during bean initialization, or <code>null</code> to leave the
* system property unchanged
*/
public String getTrustStore() {
return trustStore;
}
public void afterPropertiesSet() throws Exception {
if ((this.casValidate == null) || "".equals(casValidate)) {
throw new IllegalArgumentException("A casValidate URL must be set");
}
if (serviceProperties == null) {
throw new IllegalArgumentException(
"serviceProperties must be specified");
}
if ((trustStore != null) && (!"".equals(trustStore))) {
System.setProperty("javax.net.ssl.trustStore", trustStore);
}
}
}
@@ -0,0 +1,128 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas.ticketvalidator;
import edu.yale.its.tp.cas.client.ProxyTicketValidator;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.AuthenticationServiceException;
import net.sf.acegisecurity.BadCredentialsException;
import net.sf.acegisecurity.providers.cas.TicketResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Uses CAS' <code>ProxyTicketValidator</code> to validate a service ticket.
*
* @author Ben Alex
* @version $Id$
*/
public class CasProxyTicketValidator extends AbstractTicketValidator {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(CasProxyTicketValidator.class);
//~ Instance fields ========================================================
private String proxyCallbackUrl;
//~ Methods ================================================================
public void setProxyCallbackUrl(String proxyCallbackUrl) {
this.proxyCallbackUrl = proxyCallbackUrl;
}
/**
* Optional callback URL to obtain a proxy-granting ticket from CAS.
*
* <P>
* This callback URL belongs to the Acegi Security System for Spring
* secured application. We suggest you use CAS'
* <code>ProxyTicketReceptor</code> servlet to receive this callback and
* manage the proxy-granting ticket list. The callback URL is usually
* something like
* <code>https://www.mycompany.com/application/casProxy/receptor</code>.
* </p>
*
* <P>
* If left <code>null</code>, the <code>CasAuthenticationToken</code> will
* not have a proxy granting ticket IOU and there will be no
* proxy-granting ticket callback. Accordingly, the Acegi Securty System
* for Spring secured application will be unable to obtain a proxy ticket
* to call another CAS-secured service on behalf of the user. This is not
* really an issue for most applications.
* </p>
*
* @return the proxy callback URL, or <code>null</code> if not used
*/
public String getProxyCallbackUrl() {
return proxyCallbackUrl;
}
public TicketResponse confirmTicketValid(String serviceTicket)
throws AuthenticationException {
// Attempt to validate presented ticket using CAS' ProxyTicketValidator class
ProxyTicketValidator pv = new ProxyTicketValidator();
pv.setCasValidateUrl(super.getCasValidate());
pv.setServiceTicket(serviceTicket);
pv.setService(super.getServiceProperties().getService());
if (super.getServiceProperties().isSendRenew()) {
logger.warn(
"The current CAS ProxyTicketValidator does not support the 'renew' property. The ticket cannot be validated as having been issued by a 'renew' authentication. It is expected this will be corrected in a future version of CAS' ProxyTicketValidator.");
}
if ((this.proxyCallbackUrl != null)
&& (!"".equals(this.proxyCallbackUrl))) {
pv.setProxyCallbackUrl(proxyCallbackUrl);
}
return validateNow(pv);
}
/**
* Perform the actual remote invocation. Protected to enable replacement
* during tests.
*
* @param pv the populated <code>ProxyTicketValidator</code>
*
* @return the <code>TicketResponse</code>
*
* @throws AuthenticationServiceException
* if<code>ProxyTicketValidator</code> internally fails
* @throws BadCredentialsException DOCUMENT ME!
*/
protected TicketResponse validateNow(ProxyTicketValidator pv)
throws AuthenticationServiceException, BadCredentialsException {
try {
pv.validate();
} catch (Exception internalProxyTicketValidatorProblem) {
throw new AuthenticationServiceException(internalProxyTicketValidatorProblem
.getMessage());
}
if (!pv.isAuthenticationSuccesful()) {
throw new BadCredentialsException(pv.getErrorCode() + ": "
+ pv.getErrorMessage());
}
return new TicketResponse(pv.getUser(), pv.getProxyList(),
pv.getPgtIou());
}
}
@@ -0,0 +1,5 @@
<html>
<body>
Implementations that validate service tickets.
</body>
</html>
@@ -0,0 +1,111 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.ui.cas;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import net.sf.acegisecurity.ui.AbstractProcessingFilter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
/**
* Processes a CAS service ticket.
*
* <p>
* A service ticket consists of an opaque ticket string. It arrives at this
* filter by the user's browser successfully authenticating using CAS, and
* then receiving a HTTP redirect to a <code>service</code>. The opal ticket
* string is presented in the <code>ticket</code> request parameter. This
* filter monitors the <code>service</code> URL so it can receive the service
* ticket and process it. The CAS server knows which <code>service</code> URL
* to use via the {@link ServiceProperties#getService()} method.
* </p>
*
* <P>
* Processing the service ticket involves creating a
* <code>UsernamePasswordAuthenticationToken</code> which uses {@link
* #CAS_STATEFUL_IDENTIFIER} for the <code>principal</code> and the opaque
* ticket string as the <code>credentials</code>.
* </p>
*
* <P>
* The configured <code>AuthenticationManager</code> is expected to provide a
* provider that can recognise
* <code>UsernamePasswordAuthenticationToken</code>s containing this special
* <code>principal</code> name, and process them accordingly by validation
* with the CAS server.
* </p>
*
* <P>
* <B>Do not use this class directly.</B> Instead configure
* <code>web.xml</code> to use the {@link
* net.sf.acegisecurity.util.FilterToBeanProxy}.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class CasProcessingFilter extends AbstractProcessingFilter {
//~ Static fields/initializers =============================================
/**
* Used to identify a CAS request for a stateful user agent, such as a web
* browser.
*/
public static final String CAS_STATEFUL_IDENTIFIER = "_cas_stateful_";
/**
* Used to identify a CAS request for a stateless user agent, such as a
* remoting protocol client (eg Hessian, Burlap, SOAP etc). Results in a
* more aggressive caching strategy being used, as the absence of a
* <code>HttpSession</code> will result in a new authentication attempt on
* every request.
*/
public static final String CAS_STATELESS_IDENTIFIER = "_cas_stateless_";
//~ Methods ================================================================
/**
* This filter by default responds to
* <code>/j_acegi_cas_security_check</code>.
*
* @return the default
*/
public String getDefaultFilterProcessesUrl() {
return "/j_acegi_cas_security_check";
}
public Authentication attemptAuthentication(HttpServletRequest request)
throws AuthenticationException {
String username = CAS_STATEFUL_IDENTIFIER;
String password = request.getParameter("ticket");
if (password == null) {
password = "";
}
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username,
password);
return this.getAuthenticationManager().authenticate(authRequest);
}
public void init(FilterConfig filterConfig) throws ServletException {}
}
@@ -0,0 +1,102 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.ui.cas;
import net.sf.acegisecurity.intercept.web.AuthenticationEntryPoint;
import org.springframework.beans.factory.InitializingBean;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
/**
* Used by the <code>SecurityEnforcementFilter</code> to commence
* authentication via the Yale Central Authentication Service (CAS).
*
* <P>
* The user's browser will be redirected to the Yale CAS enterprise-wide login
* page. This page is specified by the <code>loginUrl</code> property. Once
* login is complete, the CAS login page will redirect to the page indicated
* by the <code>service</code> property. The <code>service</code> is a HTTP
* URL belonging to the current application. The <code>service</code> URL is
* monitored by the {@link CasProcessingFilter}, which will validate the CAS
* login was successful.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class CasProcessingFilterEntryPoint implements AuthenticationEntryPoint,
InitializingBean {
//~ Instance fields ========================================================
private ServiceProperties serviceProperties;
private String loginUrl;
//~ Methods ================================================================
public void setLoginUrl(String loginUrl) {
this.loginUrl = loginUrl;
}
/**
* The enterprise-wide CAS login URL. Usually something like
* <code>https://www.mycompany.com/cas/login</code>.
*
* @return the enterprise-wide CAS login URL
*/
public String getLoginUrl() {
return loginUrl;
}
public void setServiceProperties(ServiceProperties serviceProperties) {
this.serviceProperties = serviceProperties;
}
public ServiceProperties getServiceProperties() {
return serviceProperties;
}
public void afterPropertiesSet() throws Exception {
if ((loginUrl == null) || "".equals(loginUrl)) {
throw new IllegalArgumentException("loginUrl must be specified");
}
if (serviceProperties == null) {
throw new IllegalArgumentException(
"serviceProperties must be specified");
}
}
public void commence(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
String url;
if (serviceProperties.isSendRenew()) {
url = loginUrl + "?renew=true" + "&service="
+ serviceProperties.getService();
} else {
url = loginUrl + "?service=" + serviceProperties.getService();
}
((HttpServletResponse) response).sendRedirect(url);
}
}
@@ -0,0 +1,86 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.ui.cas;
import org.springframework.beans.factory.InitializingBean;
/**
* Stores properties related to this CAS service.
*
* <P>
* Each web application capable of processing CAS tickets is known as a
* service. This class stores the properties that are relevant to the local
* CAS service, being the application that is being secured by the Acegi
* Security System for Spring.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class ServiceProperties implements InitializingBean {
//~ Instance fields ========================================================
private String service;
private boolean sendRenew = false;
//~ Methods ================================================================
public void setSendRenew(boolean sendRenew) {
this.sendRenew = sendRenew;
}
/**
* Indicates whether the <code>renew</code> parameter should be sent to the
* CAS login URL and CAS validation URL.
* <P> If <code>true</code>, it will
* force CAS to authenticate the user again (even if the user has
* previously authenticated). During ticket validation it will require the
* ticket was generated as a consequence of an explicit login. High
* security applications would probably set this to <code>true</code>.
* Defaults to <code>false</code>, providing automated single sign on.
*
* @return whether to send the <code>renew</code> parameter to CAS
*/
public boolean isSendRenew() {
return sendRenew;
}
public void setService(String service) {
this.service = service;
}
/**
* Represents the service the user is authenticating to.
*
* <B>This service is the callback URL
* belonging to the local Acegi Security System for Spring secured
* application. For example,
* <code>https://www.mycompany.com/application/j_acegi_cas_security_check</code>
*
* @return the URL of the service the user is authenticating to
*/
public String getService() {
return service;
}
public void afterPropertiesSet() throws Exception {
if ((service == null) || "".equals(service)) {
throw new IllegalArgumentException("service must be specified");
}
}
}
@@ -0,0 +1,6 @@
<html>
<body>
Authenticates standard web browser users via
Yale Central Authentication Service (CAS).
</body>
</html>
@@ -15,6 +15,8 @@
package net.sf.acegisecurity.providers.dao;
import java.io.Serializable;
import net.sf.acegisecurity.GrantedAuthority;
@@ -24,7 +26,7 @@ import net.sf.acegisecurity.GrantedAuthority;
* @author Ben Alex
* @version $Id$
*/
public class User {
public class User implements Serializable {
//~ Instance fields ========================================================
private String password;
@@ -53,9 +55,10 @@ public class User {
*/
public User(String username, String password, boolean enabled,
GrantedAuthority[] authorities) throws IllegalArgumentException {
if ((username == null) || (password == null) || (authorities == null)) {
if (((username == null) || "".equals(username)) || (password == null)
|| "".equals(password) || (authorities == null)) {
throw new IllegalArgumentException(
"Cannot pass null values to constructor");
"Cannot pass null or empty values to constructor");
}
for (int i = 0; i < authorities.length; i++) {
@@ -47,7 +47,7 @@ import javax.servlet.http.HttpSession;
public class MockHttpServletRequest implements HttpServletRequest {
//~ Instance fields ========================================================
private HttpSession session;
private HttpSession session = new MockHttpSession();
private Map headersMap = new HashMap();
private Map paramMap = new HashMap();
private Principal principal;
@@ -0,0 +1,404 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas;
import junit.framework.TestCase;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.BadCredentialsException;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.GrantedAuthorityImpl;
import net.sf.acegisecurity.providers.TestingAuthenticationToken;
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import net.sf.acegisecurity.providers.cas.ticketvalidator.AbstractTicketValidator;
import net.sf.acegisecurity.ui.cas.CasProcessingFilter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
/**
* Tests {@link CasAuthenticationProvider}.
*
* @author Ben Alex
* @version $Id$
*/
public class CasAuthenticationProviderTests extends TestCase {
//~ Constructors ===========================================================
public CasAuthenticationProviderTests() {
super();
}
public CasAuthenticationProviderTests(String arg0) {
super(arg0);
}
//~ Methods ================================================================
public final void setUp() throws Exception {
super.setUp();
}
public static void main(String[] args) {
junit.textui.TestRunner.run(CasAuthenticationProviderTests.class);
}
public void testAuthenticateStateful() throws Exception {
CasAuthenticationProvider cap = new CasAuthenticationProvider();
cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
cap.setCasProxyDecider(new MockProxyDecider(true));
cap.setKey("qwerty");
StatelessTicketCache cache = new MockStatelessTicketCache();
cap.setStatelessTicketCache(cache);
cap.setTicketValidator(new MockTicketValidator(true));
cap.afterPropertiesSet();
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(CasProcessingFilter.CAS_STATEFUL_IDENTIFIER,
"ST-123");
Authentication result = cap.authenticate(token);
// Confirm ST-123 was NOT added to the cache
assertTrue(cache.getByTicketId("ST-456") == null);
if (!(result instanceof CasAuthenticationToken)) {
fail("Should have returned a CasAuthenticationToken");
}
CasAuthenticationToken casResult = (CasAuthenticationToken) result;
assertEquals("marissa", casResult.getPrincipal());
assertEquals("PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt",
casResult.getProxyGrantingTicketIou());
assertEquals("https://localhost/portal/j_acegi_cas_security_check",
casResult.getProxyList().get(0));
assertEquals("ST-123", casResult.getCredentials());
assertEquals(new GrantedAuthorityImpl("ROLE_A"),
casResult.getAuthorities()[0]);
assertEquals(new GrantedAuthorityImpl("ROLE_B"),
casResult.getAuthorities()[1]);
assertEquals(cap.getKey().hashCode(), casResult.getKeyHash());
// Now confirm the CasAuthenticationToken is automatically re-accepted.
// To ensure TicketValidator not called again, set it to deliver an exception...
cap.setTicketValidator(new MockTicketValidator(false));
Authentication laterResult = cap.authenticate(result);
assertEquals(result, laterResult);
}
public void testAuthenticateStateless() throws Exception {
CasAuthenticationProvider cap = new CasAuthenticationProvider();
cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
cap.setCasProxyDecider(new MockProxyDecider(true));
cap.setKey("qwerty");
StatelessTicketCache cache = new MockStatelessTicketCache();
cap.setStatelessTicketCache(cache);
cap.setTicketValidator(new MockTicketValidator(true));
cap.afterPropertiesSet();
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(CasProcessingFilter.CAS_STATELESS_IDENTIFIER,
"ST-456");
Authentication result = cap.authenticate(token);
// Confirm ST-456 was added to the cache
assertTrue(cache.getByTicketId("ST-456") != null);
if (!(result instanceof CasAuthenticationToken)) {
fail("Should have returned a CasAuthenticationToken");
}
assertEquals("marissa", result.getPrincipal());
assertEquals("ST-456", result.getCredentials());
// Now try to authenticate again. To ensure TicketValidator not
// called again, set it to deliver an exception...
cap.setTicketValidator(new MockTicketValidator(false));
// Previously created UsernamePasswordAuthenticationToken is OK
Authentication newResult = cap.authenticate(token);
assertEquals("marissa", newResult.getPrincipal());
assertEquals("ST-456", newResult.getCredentials());
}
public void testDetectsAMissingTicketId() throws Exception {
CasAuthenticationProvider cap = new CasAuthenticationProvider();
cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
cap.setCasProxyDecider(new MockProxyDecider(true));
cap.setKey("qwerty");
StatelessTicketCache cache = new MockStatelessTicketCache();
cap.setStatelessTicketCache(cache);
cap.setTicketValidator(new MockTicketValidator(true));
cap.afterPropertiesSet();
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(CasProcessingFilter.CAS_STATEFUL_IDENTIFIER,
"");
try {
Authentication result = cap.authenticate(token);
fail("Should have thrown BadCredentialsException");
} catch (BadCredentialsException expected) {
assertEquals("Failed to provide a CAS service ticket to validate",
expected.getMessage());
}
}
public void testDetectsAnInvalidKey() throws Exception {
CasAuthenticationProvider cap = new CasAuthenticationProvider();
cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
cap.setCasProxyDecider(new MockProxyDecider(true));
cap.setKey("qwerty");
StatelessTicketCache cache = new MockStatelessTicketCache();
cap.setStatelessTicketCache(cache);
cap.setTicketValidator(new MockTicketValidator(true));
cap.afterPropertiesSet();
CasAuthenticationToken token = new CasAuthenticationToken("WRONG_KEY",
"test", "credentials",
new GrantedAuthority[] {new GrantedAuthorityImpl("XX")},
new Vector(), "IOU-xxx");
try {
Authentication result = cap.authenticate(token);
fail("Should have thrown BadCredentialsException");
} catch (BadCredentialsException expected) {
assertEquals("The presented CasAuthenticationToken does not contain the expected key",
expected.getMessage());
}
}
public void testDetectsMissingAuthoritiesPopulator()
throws Exception {
CasAuthenticationProvider cap = new CasAuthenticationProvider();
cap.setCasProxyDecider(new MockProxyDecider());
cap.setKey("qwerty");
cap.setStatelessTicketCache(new MockStatelessTicketCache());
cap.setTicketValidator(new MockTicketValidator(true));
try {
cap.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("A casAuthoritiesPopulator must be set",
expected.getMessage());
}
}
public void testDetectsMissingKey() throws Exception {
CasAuthenticationProvider cap = new CasAuthenticationProvider();
cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
cap.setCasProxyDecider(new MockProxyDecider());
cap.setStatelessTicketCache(new MockStatelessTicketCache());
cap.setTicketValidator(new MockTicketValidator(true));
try {
cap.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("A Key is required so CasAuthenticationProvider can identify tokens it previously authenticated",
expected.getMessage());
}
}
public void testDetectsMissingProxyDecider() throws Exception {
CasAuthenticationProvider cap = new CasAuthenticationProvider();
cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
cap.setKey("qwerty");
cap.setStatelessTicketCache(new MockStatelessTicketCache());
cap.setTicketValidator(new MockTicketValidator(true));
try {
cap.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("A casProxyDecider must be set", expected.getMessage());
}
}
public void testDetectsMissingStatelessTicketCache()
throws Exception {
CasAuthenticationProvider cap = new CasAuthenticationProvider();
cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
cap.setCasProxyDecider(new MockProxyDecider());
cap.setKey("qwerty");
cap.setTicketValidator(new MockTicketValidator(true));
try {
cap.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("A statelessTicketCache must be set",
expected.getMessage());
}
}
public void testDetectsMissingTicketValidator() throws Exception {
CasAuthenticationProvider cap = new CasAuthenticationProvider();
cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
cap.setCasProxyDecider(new MockProxyDecider(true));
cap.setKey("qwerty");
cap.setStatelessTicketCache(new MockStatelessTicketCache());
try {
cap.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("A ticketValidator must be set", expected.getMessage());
}
}
public void testGettersSetters() throws Exception {
CasAuthenticationProvider cap = new CasAuthenticationProvider();
cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
cap.setCasProxyDecider(new MockProxyDecider());
cap.setKey("qwerty");
cap.setStatelessTicketCache(new MockStatelessTicketCache());
cap.setTicketValidator(new MockTicketValidator(true));
cap.afterPropertiesSet();
assertTrue(cap.getCasAuthoritiesPopulator() != null);
assertTrue(cap.getCasProxyDecider() != null);
assertEquals("qwerty", cap.getKey());
assertTrue(cap.getStatelessTicketCache() != null);
assertTrue(cap.getTicketValidator() != null);
}
public void testIgnoresClassesItDoesNotSupport() throws Exception {
CasAuthenticationProvider cap = new CasAuthenticationProvider();
cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
cap.setCasProxyDecider(new MockProxyDecider());
cap.setKey("qwerty");
cap.setStatelessTicketCache(new MockStatelessTicketCache());
cap.setTicketValidator(new MockTicketValidator(true));
cap.afterPropertiesSet();
TestingAuthenticationToken token = new TestingAuthenticationToken("user",
"password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_A")});
assertFalse(cap.supports(TestingAuthenticationToken.class));
// Try it anyway
assertEquals(null, cap.authenticate(token));
}
public void testIgnoresUsernamePasswordAuthenticationTokensWithoutCasIdentifiersAsPrincipal()
throws Exception {
CasAuthenticationProvider cap = new CasAuthenticationProvider();
cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
cap.setCasProxyDecider(new MockProxyDecider());
cap.setKey("qwerty");
cap.setStatelessTicketCache(new MockStatelessTicketCache());
cap.setTicketValidator(new MockTicketValidator(true));
cap.afterPropertiesSet();
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("some_normal_user",
"password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_A")});
assertEquals(null, cap.authenticate(token));
}
public void testSupports() {
CasAuthenticationProvider cap = new CasAuthenticationProvider();
assertTrue(cap.supports(UsernamePasswordAuthenticationToken.class));
assertTrue(cap.supports(CasAuthenticationToken.class));
}
//~ Inner Classes ==========================================================
private class MockAuthoritiesPopulator implements CasAuthoritiesPopulator {
public GrantedAuthority[] getAuthorities(String casUserId)
throws AuthenticationException {
return new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_A"), new GrantedAuthorityImpl(
"ROLE_B")};
}
}
private class MockProxyDecider implements CasProxyDecider {
private boolean acceptProxy;
public MockProxyDecider(boolean acceptProxy) {
this.acceptProxy = acceptProxy;
}
private MockProxyDecider() {
super();
}
public void confirmProxyListTrusted(List proxyList)
throws ProxyUntrustedException {
if (acceptProxy) {
return;
} else {
throw new ProxyUntrustedException("As requested from mock");
}
}
}
private class MockStatelessTicketCache implements StatelessTicketCache {
private Map cache = new HashMap();
public CasAuthenticationToken getByTicketId(String serviceTicket) {
return (CasAuthenticationToken) cache.get(serviceTicket);
}
public void putTicketInCache(CasAuthenticationToken token) {
cache.put(token.getCredentials().toString(), token);
}
public void removeTicketFromCache(CasAuthenticationToken token) {
throw new UnsupportedOperationException(
"mock method not implemented");
}
public void removeTicketFromCache(String serviceTicket) {
throw new UnsupportedOperationException(
"mock method not implemented");
}
}
private class MockTicketValidator extends AbstractTicketValidator {
private boolean returnTicket;
public MockTicketValidator(boolean returnTicket) {
this.returnTicket = returnTicket;
}
private MockTicketValidator() {
super();
}
public TicketResponse confirmTicketValid(String serviceTicket)
throws AuthenticationException {
if (returnTicket) {
List list = new Vector();
list.add("https://localhost/portal/j_acegi_cas_security_check");
return new TicketResponse("marissa", list,
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
}
throw new BadCredentialsException("As requested from mock");
}
}
}
@@ -0,0 +1,283 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas;
import junit.framework.TestCase;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.GrantedAuthorityImpl;
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import java.util.List;
import java.util.Vector;
/**
* Tests {@link CasAuthenticationToken}.
*
* @author Ben Alex
* @version $Id$
*/
public class CasAuthenticationTokenTests extends TestCase {
//~ Constructors ===========================================================
public CasAuthenticationTokenTests() {
super();
}
public CasAuthenticationTokenTests(String arg0) {
super(arg0);
}
//~ Methods ================================================================
public final void setUp() throws Exception {
super.setUp();
}
public static void main(String[] args) {
junit.textui.TestRunner.run(CasAuthenticationTokenTests.class);
}
public void testConstructorRejectsNulls() {
try {
new CasAuthenticationToken(null, "Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")}, new Vector(),
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
try {
new CasAuthenticationToken("key", null, "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")}, new Vector(),
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
try {
new CasAuthenticationToken("key", "Test", null,
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")}, new Vector(),
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
try {
new CasAuthenticationToken("key", "Test", "Password", null,
new Vector(),
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
try {
new CasAuthenticationToken("key", "Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")}, null,
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
try {
new CasAuthenticationToken("key", "Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")}, new Vector(), null);
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
try {
new CasAuthenticationToken("key", "Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), null, new GrantedAuthorityImpl(
"ROLE_TWO")}, new Vector(),
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
}
public void testEqualsWhenEqual() {
List proxyList1 = new Vector();
proxyList1.add("https://localhost/newPortal/j_acegi_cas_security_check");
CasAuthenticationToken token1 = new CasAuthenticationToken("key",
"Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")}, proxyList1,
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
List proxyList2 = new Vector();
proxyList2.add("https://localhost/newPortal/j_acegi_cas_security_check");
CasAuthenticationToken token2 = new CasAuthenticationToken("key",
"Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")}, proxyList2,
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
assertEquals(token1, token2);
}
public void testGetters() {
// Build the proxy list returned in the ticket from CAS
List proxyList = new Vector();
proxyList.add("https://localhost/newPortal/j_acegi_cas_security_check");
CasAuthenticationToken token = new CasAuthenticationToken("key",
"Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")}, proxyList,
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
assertEquals("key".hashCode(), token.getKeyHash());
assertEquals("Test", token.getPrincipal());
assertEquals("Password", token.getCredentials());
assertEquals("ROLE_ONE", token.getAuthorities()[0].getAuthority());
assertEquals("ROLE_TWO", token.getAuthorities()[1].getAuthority());
assertEquals("PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt",
token.getProxyGrantingTicketIou());
assertEquals(proxyList, token.getProxyList());
}
public void testNoArgConstructor() {
try {
new CasAuthenticationToken();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
}
public void testNotEqualsDueToAbstractParentEqualsCheck() {
List proxyList1 = new Vector();
proxyList1.add("https://localhost/newPortal/j_acegi_cas_security_check");
CasAuthenticationToken token1 = new CasAuthenticationToken("key",
"Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")}, proxyList1,
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
List proxyList2 = new Vector();
proxyList2.add("https://localhost/newPortal/j_acegi_cas_security_check");
CasAuthenticationToken token2 = new CasAuthenticationToken("key",
"OTHER_VALUE", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")}, proxyList2,
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
assertTrue(!token1.equals(token2));
}
public void testNotEqualsDueToDifferentAuthenticationClass() {
List proxyList1 = new Vector();
proxyList1.add("https://localhost/newPortal/j_acegi_cas_security_check");
CasAuthenticationToken token1 = new CasAuthenticationToken("key",
"Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")}, proxyList1,
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
UsernamePasswordAuthenticationToken token2 = new UsernamePasswordAuthenticationToken("Test",
"Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")});
token2.setAuthenticated(true);
assertTrue(!token1.equals(token2));
}
public void testNotEqualsDueToProxyGrantingTicket() {
List proxyList1 = new Vector();
proxyList1.add("https://localhost/newPortal/j_acegi_cas_security_check");
CasAuthenticationToken token1 = new CasAuthenticationToken("key",
"Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")}, proxyList1,
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
List proxyList2 = new Vector();
proxyList2.add("https://localhost/newPortal/j_acegi_cas_security_check");
CasAuthenticationToken token2 = new CasAuthenticationToken("key",
"Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")}, proxyList2, "PGTIOU-SOME_OTHER_VALUE");
assertTrue(!token1.equals(token2));
}
public void testNotEqualsDueToProxyList() {
List proxyList1 = new Vector();
proxyList1.add("https://localhost/newPortal/j_acegi_cas_security_check");
CasAuthenticationToken token1 = new CasAuthenticationToken("key",
"Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")}, proxyList1,
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
List proxyList2 = new Vector();
proxyList2.add(
"https://localhost/SOME_OTHER_PORTAL/j_acegi_cas_security_check");
CasAuthenticationToken token2 = new CasAuthenticationToken("key",
"Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")}, proxyList2,
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
assertTrue(!token1.equals(token2));
}
public void testSetAuthenticatedIgnored() {
CasAuthenticationToken token = new CasAuthenticationToken("key",
"Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")}, new Vector(),
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
assertTrue(token.isAuthenticated());
token.setAuthenticated(false); // ignored
assertTrue(token.isAuthenticated());
}
public void testToString() {
CasAuthenticationToken token = new CasAuthenticationToken("key",
"Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")}, new Vector(),
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
String result = token.toString();
assertTrue(result.lastIndexOf("Proxy List:") != -1);
assertTrue(result.lastIndexOf("Proxy-Granting Ticket IOU:") != -1);
assertTrue(result.lastIndexOf("Credentials (Service/Proxy Ticket):") != -1);
}
}
@@ -0,0 +1,102 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas;
import junit.framework.TestCase;
import java.util.List;
import java.util.Vector;
/**
* Tests {@link TicketResponse}.
*
* @author Ben Alex
* @version $Id$
*/
public class TicketResponseTests extends TestCase {
//~ Constructors ===========================================================
public TicketResponseTests() {
super();
}
public TicketResponseTests(String arg0) {
super(arg0);
}
//~ Methods ================================================================
public final void setUp() throws Exception {
super.setUp();
}
public static void main(String[] args) {
junit.textui.TestRunner.run(TicketResponseTests.class);
}
public void testConstructorAcceptsNullProxyGrantingTicketIOU() {
TicketResponse ticket = new TicketResponse("marissa", new Vector(), null);
assertEquals("", ticket.getProxyGrantingTicketIou());
}
public void testConstructorAcceptsNullProxyList() {
TicketResponse ticket = new TicketResponse("marissa", null,
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
assertEquals(new Vector(), ticket.getProxyList());
}
public void testConstructorRejectsNullUser() {
try {
new TicketResponse(null, new Vector(),
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
}
public void testGetters() {
// Build the proxy list returned in the ticket from CAS
List proxyList = new Vector();
proxyList.add("https://localhost/newPortal/j_acegi_cas_security_check");
TicketResponse ticket = new TicketResponse("marissa", proxyList,
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
assertEquals("marissa", ticket.getUser());
assertEquals(proxyList, ticket.getProxyList());
assertEquals("PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt",
ticket.getProxyGrantingTicketIou());
}
public void testNoArgConstructor() {
try {
new TicketResponse();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
}
public void testToString() {
TicketResponse ticket = new TicketResponse("marissa", null,
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
String result = ticket.toString();
assertTrue(result.lastIndexOf("Proxy List:") != -1);
assertTrue(result.lastIndexOf("Proxy-Granting Ticket IOU:") != -1);
assertTrue(result.lastIndexOf("User:") != -1);
}
}
@@ -0,0 +1,89 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas.cache;
import junit.framework.TestCase;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.GrantedAuthorityImpl;
import net.sf.acegisecurity.providers.cas.CasAuthenticationToken;
import java.util.List;
import java.util.Vector;
/**
* Tests {@link EhCacheBasedTicketCache}.
*
* @author Ben Alex
* @version $Id$
*/
public class EhCacheBasedTicketCacheTests extends TestCase {
//~ Constructors ===========================================================
public EhCacheBasedTicketCacheTests() {
super();
}
public EhCacheBasedTicketCacheTests(String arg0) {
super(arg0);
}
//~ Methods ================================================================
public final void setUp() throws Exception {
super.setUp();
}
public static void main(String[] args) {
junit.textui.TestRunner.run(EhCacheBasedTicketCacheTests.class);
}
public void testCacheOperation() throws Exception {
EhCacheBasedTicketCache cache = new EhCacheBasedTicketCache();
cache.afterPropertiesSet();
// Check it gets stored in the cache
cache.putTicketInCache(getToken());
assertEquals(getToken(),
cache.getByTicketId("ST-0-ER94xMJmn6pha35CQRoZ"));
// Check it gets removed from the cache
cache.removeTicketFromCache(getToken());
assertNull(cache.getByTicketId("ST-0-ER94xMJmn6pha35CQRoZ"));
// Check it doesn't return values for null or unknown service tickets
assertNull(cache.getByTicketId(null));
assertNull(cache.getByTicketId("UNKNOWN_SERVICE_TICKET"));
}
public void testGettersSetters() {
EhCacheBasedTicketCache cache = new EhCacheBasedTicketCache();
cache.setMinutesToIdle(5);
assertEquals(5, cache.getMinutesToIdle());
}
private CasAuthenticationToken getToken() {
List proxyList = new Vector();
proxyList.add("https://localhost/newPortal/j_acegi_cas_security_check");
return new CasAuthenticationToken("key", "marissa",
"ST-0-ER94xMJmn6pha35CQRoZ",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")}, proxyList,
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
}
}
@@ -0,0 +1,148 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas.populator;
import junit.framework.TestCase;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.GrantedAuthorityImpl;
import net.sf.acegisecurity.providers.dao.AuthenticationDao;
import net.sf.acegisecurity.providers.dao.User;
import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataRetrievalFailureException;
/**
* Tests {@link DaoCasAuthoritiesPopulator}.
*
* @author Ben Alex
* @version $Id$
*/
public class DaoCasAuthoritiesPopulatorTests extends TestCase {
//~ Constructors ===========================================================
public DaoCasAuthoritiesPopulatorTests() {
super();
}
public DaoCasAuthoritiesPopulatorTests(String arg0) {
super(arg0);
}
//~ Methods ================================================================
public final void setUp() throws Exception {
super.setUp();
}
public static void main(String[] args) {
junit.textui.TestRunner.run(DaoCasAuthoritiesPopulatorTests.class);
}
public void testDetectsMissingAuthenticationDao() throws Exception {
DaoCasAuthoritiesPopulator populator = new DaoCasAuthoritiesPopulator();
try {
populator.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("An authenticationDao must be set",
expected.getMessage());
}
}
public void testGetGrantedAuthoritiesForInvalidUsername()
throws Exception {
DaoCasAuthoritiesPopulator populator = new DaoCasAuthoritiesPopulator();
populator.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
populator.afterPropertiesSet();
try {
populator.getAuthorities("scott");
fail("Should have thrown UsernameNotFoundException");
} catch (UsernameNotFoundException expected) {
assertTrue(true);
}
}
public void testGetGrantedAuthoritiesForValidUsername()
throws Exception {
DaoCasAuthoritiesPopulator populator = new DaoCasAuthoritiesPopulator();
populator.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
populator.afterPropertiesSet();
GrantedAuthority[] results = populator.getAuthorities("marissa");
assertEquals(2, results.length);
assertEquals(new GrantedAuthorityImpl("ROLE_ONE"), results[0]);
assertEquals(new GrantedAuthorityImpl("ROLE_TWO"), results[1]);
}
public void testGetGrantedAuthoritiesWhenDaoThrowsException()
throws Exception {
DaoCasAuthoritiesPopulator populator = new DaoCasAuthoritiesPopulator();
populator.setAuthenticationDao(new MockAuthenticationDaoSimulateBackendError());
populator.afterPropertiesSet();
try {
populator.getAuthorities("THE_DAO_WILL_FAIL");
fail("Should have thrown DataRetrievalFailureException");
} catch (DataRetrievalFailureException expected) {
assertTrue(true);
}
}
public void testGettersSetters() {
DaoCasAuthoritiesPopulator populator = new DaoCasAuthoritiesPopulator();
AuthenticationDao dao = new MockAuthenticationDaoUserMarissa();
populator.setAuthenticationDao(dao);
assertEquals(dao, populator.getAuthenticationDao());
}
//~ Inner Classes ==========================================================
private class MockAuthenticationDaoSimulateBackendError
implements AuthenticationDao {
public long getRefreshDuration() {
return 0;
}
public User loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
throw new DataRetrievalFailureException(
"This mock simulator is designed to fail");
}
}
private class MockAuthenticationDaoUserMarissa implements AuthenticationDao {
public long getRefreshDuration() {
return 0;
}
public User loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
if ("marissa".equals(username)) {
return new User("marissa", "koala", true,
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")});
} else {
throw new UsernameNotFoundException("Could not find: "
+ username);
}
}
}
}
@@ -0,0 +1,66 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas.proxy;
import junit.framework.TestCase;
import java.util.Vector;
/**
* Tests {@link AcceptAnyCasProxy}.
*
* @author Ben Alex
* @version $Id$
*/
public class AcceptAnyCasProxyTests extends TestCase {
//~ Constructors ===========================================================
public AcceptAnyCasProxyTests() {
super();
}
public AcceptAnyCasProxyTests(String arg0) {
super(arg0);
}
//~ Methods ================================================================
public final void setUp() throws Exception {
super.setUp();
}
public static void main(String[] args) {
junit.textui.TestRunner.run(AcceptAnyCasProxyTests.class);
}
public void testDoesNotAcceptNull() {
AcceptAnyCasProxy proxyDecider = new AcceptAnyCasProxy();
try {
proxyDecider.confirmProxyListTrusted(null);
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("proxyList cannot be null", expected.getMessage());
}
}
public void testNormalOperation() {
AcceptAnyCasProxy proxyDecider = new AcceptAnyCasProxy();
proxyDecider.confirmProxyListTrusted(new Vector());
assertTrue(true); // as no Exception thrown
}
}
@@ -0,0 +1,141 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas.proxy;
import junit.framework.TestCase;
import net.sf.acegisecurity.providers.cas.ProxyUntrustedException;
import java.util.List;
import java.util.Vector;
/**
* Tests {@link NamedCasProxyDecider}.
*
* @author Ben Alex
* @version $Id$
*/
public class NamedCasProxyDeciderTests extends TestCase {
//~ Constructors ===========================================================
public NamedCasProxyDeciderTests() {
super();
}
public NamedCasProxyDeciderTests(String arg0) {
super(arg0);
}
//~ Methods ================================================================
public final void setUp() throws Exception {
super.setUp();
}
public static void main(String[] args) {
junit.textui.TestRunner.run(NamedCasProxyDeciderTests.class);
}
public void testAcceptsIfNearestProxyIsAuthorized()
throws Exception {
NamedCasProxyDecider proxyDecider = new NamedCasProxyDecider();
// Build the ticket returned from CAS
List proxyList = new Vector();
proxyList.add("https://localhost/newPortal/j_acegi_cas_security_check");
// Build the list of valid nearest proxies
List validProxies = new Vector();
validProxies.add("https://localhost/portal/j_acegi_cas_security_check");
validProxies.add(
"https://localhost/newPortal/j_acegi_cas_security_check");
proxyDecider.setValidProxies(validProxies);
proxyDecider.afterPropertiesSet();
proxyDecider.confirmProxyListTrusted(proxyList);
assertTrue(true);
}
public void testAcceptsIfNoProxiesInTicket() {
NamedCasProxyDecider proxyDecider = new NamedCasProxyDecider();
List proxyList = new Vector(); // no proxies in list
proxyDecider.confirmProxyListTrusted(proxyList);
assertTrue(true);
}
public void testDetectsMissingValidProxiesList() throws Exception {
NamedCasProxyDecider proxyDecider = new NamedCasProxyDecider();
try {
proxyDecider.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("A validProxies list must be set",
expected.getMessage());
}
}
public void testDoesNotAcceptNull() {
NamedCasProxyDecider proxyDecider = new NamedCasProxyDecider();
try {
proxyDecider.confirmProxyListTrusted(null);
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("proxyList cannot be null", expected.getMessage());
}
}
public void testGettersSetters() {
NamedCasProxyDecider proxyDecider = new NamedCasProxyDecider();
// Build the list of valid nearest proxies
List validProxies = new Vector();
validProxies.add("https://localhost/portal/j_acegi_cas_security_check");
validProxies.add(
"https://localhost/newPortal/j_acegi_cas_security_check");
proxyDecider.setValidProxies(validProxies);
assertEquals(validProxies, proxyDecider.getValidProxies());
}
public void testRejectsIfNearestProxyIsNotAuthorized()
throws Exception {
NamedCasProxyDecider proxyDecider = new NamedCasProxyDecider();
// Build the ticket returned from CAS
List proxyList = new Vector();
proxyList.add(
"https://localhost/untrustedWebApp/j_acegi_cas_security_check");
// Build the list of valid nearest proxies
List validProxies = new Vector();
validProxies.add("https://localhost/portal/j_acegi_cas_security_check");
validProxies.add(
"https://localhost/newPortal/j_acegi_cas_security_check");
proxyDecider.setValidProxies(validProxies);
proxyDecider.afterPropertiesSet();
try {
proxyDecider.confirmProxyListTrusted(proxyList);
fail("Should have thrown ProxyUntrustedException");
} catch (ProxyUntrustedException expected) {
assertTrue(true);
}
}
}
@@ -0,0 +1,84 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas.proxy;
import junit.framework.TestCase;
import net.sf.acegisecurity.providers.cas.ProxyUntrustedException;
import java.util.List;
import java.util.Vector;
/**
* Tests {@link RejectProxyTickets}.
*
* @author Ben Alex
* @version $Id$
*/
public class RejectProxyTicketsTests extends TestCase {
//~ Constructors ===========================================================
public RejectProxyTicketsTests() {
super();
}
public RejectProxyTicketsTests(String arg0) {
super(arg0);
}
//~ Methods ================================================================
public final void setUp() throws Exception {
super.setUp();
}
public static void main(String[] args) {
junit.textui.TestRunner.run(RejectProxyTicketsTests.class);
}
public void testAcceptsIfNoProxiesInTicket() {
RejectProxyTickets proxyDecider = new RejectProxyTickets();
List proxyList = new Vector(); // no proxies in list
proxyDecider.confirmProxyListTrusted(proxyList);
assertTrue(true);
}
public void testDoesNotAcceptNull() {
RejectProxyTickets proxyDecider = new RejectProxyTickets();
try {
proxyDecider.confirmProxyListTrusted(null);
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("proxyList cannot be null", expected.getMessage());
}
}
public void testRejectsIfAnyProxyInList() {
RejectProxyTickets proxyDecider = new RejectProxyTickets();
List proxyList = new Vector();
proxyList.add("https://localhost/webApp/j_acegi_cas_security_check");
try {
proxyDecider.confirmProxyListTrusted(proxyList);
fail("Should have thrown ProxyUntrustedException");
} catch (ProxyUntrustedException expected) {
assertTrue(true);
}
}
}
@@ -0,0 +1,143 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas.ticketvalidator;
import junit.framework.TestCase;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.BadCredentialsException;
import net.sf.acegisecurity.providers.cas.TicketResponse;
import net.sf.acegisecurity.ui.cas.ServiceProperties;
import java.util.Vector;
/**
* Tests {@link AbstractTicketValidator}.
*
* @author Ben Alex
* @version $Id$
*/
public class AbstractTicketValidatorTests extends TestCase {
//~ Constructors ===========================================================
public AbstractTicketValidatorTests() {
super();
}
public AbstractTicketValidatorTests(String arg0) {
super(arg0);
}
//~ Methods ================================================================
public final void setUp() throws Exception {
super.setUp();
}
public static void main(String[] args) {
junit.textui.TestRunner.run(AbstractTicketValidatorTests.class);
}
public void testDetectsMissingCasValidate() throws Exception {
AbstractTicketValidator tv = new MockAbstractTicketValidator();
tv.setServiceProperties(new ServiceProperties());
try {
tv.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("A casValidate URL must be set", expected.getMessage());
}
}
public void testDetectsMissingServiceProperties() throws Exception {
AbstractTicketValidator tv = new MockAbstractTicketValidator();
tv.setCasValidate("https://company.com/cas/proxyvalidate");
try {
tv.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("serviceProperties must be specified",
expected.getMessage());
}
}
public void testGetters() throws Exception {
AbstractTicketValidator tv = new MockAbstractTicketValidator();
tv.setCasValidate("https://company.com/cas/proxyvalidate");
assertEquals("https://company.com/cas/proxyvalidate",
tv.getCasValidate());
tv.setServiceProperties(new ServiceProperties());
assertTrue(tv.getServiceProperties() != null);
tv.afterPropertiesSet();
tv.setTrustStore("/some/file/cacerts");
assertEquals("/some/file/cacerts", tv.getTrustStore());
}
public void testSystemPropertySetDuringAfterPropertiesSet()
throws Exception {
AbstractTicketValidator tv = new MockAbstractTicketValidator();
tv.setCasValidate("https://company.com/cas/proxyvalidate");
assertEquals("https://company.com/cas/proxyvalidate",
tv.getCasValidate());
tv.setServiceProperties(new ServiceProperties());
assertTrue(tv.getServiceProperties() != null);
tv.setTrustStore("/some/file/cacerts");
assertEquals("/some/file/cacerts", tv.getTrustStore());
String before = System.getProperty("javax.net.ssl.trustStore");
tv.afterPropertiesSet();
assertEquals("/some/file/cacerts",
System.getProperty("javax.net.ssl.trustStore"));
if (before == null) {
System.setProperty("javax.net.ssl.trustStore", "");
} else {
System.setProperty("javax.net.ssl.trustStore", before);
}
}
//~ Inner Classes ==========================================================
private class MockAbstractTicketValidator extends AbstractTicketValidator {
private boolean returnTicket;
public MockAbstractTicketValidator(boolean returnTicket) {
this.returnTicket = returnTicket;
}
private MockAbstractTicketValidator() {
super();
}
public TicketResponse confirmTicketValid(String serviceTicket)
throws AuthenticationException {
if (returnTicket) {
return new TicketResponse("user", new Vector(),
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
}
throw new BadCredentialsException("As requested by mock");
}
}
}
@@ -0,0 +1,138 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.providers.cas.ticketvalidator;
import edu.yale.its.tp.cas.client.ProxyTicketValidator;
import junit.framework.TestCase;
import net.sf.acegisecurity.AuthenticationServiceException;
import net.sf.acegisecurity.BadCredentialsException;
import net.sf.acegisecurity.providers.cas.TicketResponse;
import net.sf.acegisecurity.ui.cas.ServiceProperties;
import java.util.Vector;
/**
* Tests {@link CasProxyTicketValidator}.
*
* @author Ben Alex
* @version $Id$
*/
public class CasProxyTicketValidatorTests extends TestCase {
//~ Constructors ===========================================================
public CasProxyTicketValidatorTests() {
super();
}
public CasProxyTicketValidatorTests(String arg0) {
super(arg0);
}
//~ Methods ================================================================
public final void setUp() throws Exception {
super.setUp();
}
public static void main(String[] args) {
junit.textui.TestRunner.run(CasProxyTicketValidatorTests.class);
}
public void testGetters() {
CasProxyTicketValidator tv = new CasProxyTicketValidator();
tv.setProxyCallbackUrl("http://my.com/webapp/casProxy/someValidator");
assertEquals("http://my.com/webapp/casProxy/someValidator",
tv.getProxyCallbackUrl());
}
public void testNormalOperation() {
ServiceProperties sp = new ServiceProperties();
sp.setSendRenew(true);
sp.setService("https://my.com/webapp//j_acegi_cas_security_check");
CasProxyTicketValidator tv = new MockCasProxyTicketValidator(true, false);
tv.setCasValidate("https://company.com/cas/proxyvalidate");
tv.setServiceProperties(sp);
tv.setProxyCallbackUrl("http://my.com/webapp/casProxy/someValidator");
TicketResponse response = tv.confirmTicketValid(
"ST-0-ER94xMJmn6pha35CQRoZ");
assertEquals("user", response.getUser());
}
public void testProxyTicketValidatorInternalExceptionsGracefullyHandled() {
CasProxyTicketValidator tv = new MockCasProxyTicketValidator(false, true);
tv.setCasValidate("https://company.com/cas/proxyvalidate");
tv.setServiceProperties(new ServiceProperties());
tv.setProxyCallbackUrl("http://my.com/webapp/casProxy/someValidator");
try {
tv.confirmTicketValid("ST-0-ER94xMJmn6pha35CQRoZ");
fail("Should have thrown AuthenticationServiceException");
} catch (AuthenticationServiceException expected) {
assertTrue(true);
}
}
public void testValidationFailsOkAndOperationWithoutAProxyCallbackUrl() {
CasProxyTicketValidator tv = new MockCasProxyTicketValidator(false,
false);
tv.setCasValidate("https://company.com/cas/proxyvalidate");
tv.setServiceProperties(new ServiceProperties());
try {
tv.confirmTicketValid("ST-0-ER94xMJmn6pha35CQRoZ");
fail("Should have thrown BadCredentialsExpected");
} catch (BadCredentialsException expected) {
assertTrue(true);
}
}
//~ Inner Classes ==========================================================
private class MockCasProxyTicketValidator extends CasProxyTicketValidator {
private boolean returnTicket;
private boolean throwAuthenticationServiceException;
public MockCasProxyTicketValidator(boolean returnTicket,
boolean throwAuthenticationServiceException) {
this.returnTicket = returnTicket;
this.throwAuthenticationServiceException = throwAuthenticationServiceException;
}
private MockCasProxyTicketValidator() {
super();
}
protected TicketResponse validateNow(ProxyTicketValidator pv)
throws AuthenticationServiceException, BadCredentialsException {
if (returnTicket) {
return new TicketResponse("user", new Vector(),
"PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
}
if (throwAuthenticationServiceException) {
throw new AuthenticationServiceException("As requested by mock");
}
throw new BadCredentialsException("As requested by mock");
}
}
}
@@ -0,0 +1,126 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.ui.cas;
import junit.framework.TestCase;
import net.sf.acegisecurity.MockHttpServletRequest;
import net.sf.acegisecurity.MockHttpServletResponse;
/**
* Tests {@link CasProcessingFilterEntryPoint}.
*
* @author Ben Alex
* @version $Id$
*/
public class CasProcessingFilterEntryPointTests extends TestCase {
//~ Constructors ===========================================================
public CasProcessingFilterEntryPointTests() {
super();
}
public CasProcessingFilterEntryPointTests(String arg0) {
super(arg0);
}
//~ Methods ================================================================
public final void setUp() throws Exception {
super.setUp();
}
public static void main(String[] args) {
junit.textui.TestRunner.run(CasProcessingFilterEntryPointTests.class);
}
public void testDetectsMissingLoginFormUrl() throws Exception {
CasProcessingFilterEntryPoint ep = new CasProcessingFilterEntryPoint();
ep.setServiceProperties(new ServiceProperties());
try {
ep.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("loginUrl must be specified", expected.getMessage());
}
}
public void testDetectsMissingServiceProperties() throws Exception {
CasProcessingFilterEntryPoint ep = new CasProcessingFilterEntryPoint();
ep.setLoginUrl("https://cas/login");
try {
ep.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("serviceProperties must be specified",
expected.getMessage());
}
}
public void testGettersSetters() {
CasProcessingFilterEntryPoint ep = new CasProcessingFilterEntryPoint();
ep.setLoginUrl("https://cas/login");
assertEquals("https://cas/login", ep.getLoginUrl());
ep.setServiceProperties(new ServiceProperties());
assertTrue(ep.getServiceProperties() != null);
}
public void testNormalOperationWithRenewFalse() throws Exception {
ServiceProperties sp = new ServiceProperties();
sp.setSendRenew(false);
sp.setService(
"https://mycompany.com/bigWebApp/j_acegi_cas_security_check");
CasProcessingFilterEntryPoint ep = new CasProcessingFilterEntryPoint();
ep.setLoginUrl("https://cas/login");
ep.setServiceProperties(sp);
MockHttpServletRequest request = new MockHttpServletRequest(
"/some_path");
MockHttpServletResponse response = new MockHttpServletResponse();
ep.afterPropertiesSet();
ep.commence(request, response);
assertEquals("https://cas/login?service=https://mycompany.com/bigWebApp/j_acegi_cas_security_check",
response.getRedirect());
}
public void testNormalOperationWithRenewTrue() throws Exception {
ServiceProperties sp = new ServiceProperties();
sp.setSendRenew(true);
sp.setService(
"https://mycompany.com/bigWebApp/j_acegi_cas_security_check");
CasProcessingFilterEntryPoint ep = new CasProcessingFilterEntryPoint();
ep.setLoginUrl("https://cas/login");
ep.setServiceProperties(sp);
MockHttpServletRequest request = new MockHttpServletRequest(
"/some_path");
MockHttpServletResponse response = new MockHttpServletResponse();
ep.afterPropertiesSet();
ep.commence(request, response);
assertEquals("https://cas/login?renew=true&service=https://mycompany.com/bigWebApp/j_acegi_cas_security_check",
response.getRedirect());
}
}
@@ -0,0 +1,93 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.ui.cas;
import junit.framework.TestCase;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.MockAuthenticationManager;
import net.sf.acegisecurity.MockHttpServletRequest;
import net.sf.acegisecurity.MockHttpSession;
/**
* Tests {@link CasProcessingFilter}.
*
* @author Ben Alex
* @version $Id$
*/
public class CasProcessingFilterTests extends TestCase {
//~ Constructors ===========================================================
public CasProcessingFilterTests() {
super();
}
public CasProcessingFilterTests(String arg0) {
super(arg0);
}
//~ Methods ================================================================
public final void setUp() throws Exception {
super.setUp();
}
public static void main(String[] args) {
junit.textui.TestRunner.run(CasProcessingFilterTests.class);
}
public void testGetters() {
CasProcessingFilter filter = new CasProcessingFilter();
assertEquals("/j_acegi_cas_security_check",
filter.getDefaultFilterProcessesUrl());
}
public void testNormalOperation() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest(null,
new MockHttpSession());
request.setParameter("ticket", "ST-0-ER94xMJmn6pha35CQRoZ");
MockAuthenticationManager authMgr = new MockAuthenticationManager(true);
CasProcessingFilter filter = new CasProcessingFilter();
filter.setAuthenticationManager(authMgr);
filter.init(null);
Authentication result = filter.attemptAuthentication(request);
assertTrue(result != null);
}
public void testNullServiceTicketHandledGracefully()
throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest(null,
new MockHttpSession());
MockAuthenticationManager authMgr = new MockAuthenticationManager(false);
CasProcessingFilter filter = new CasProcessingFilter();
filter.setAuthenticationManager(authMgr);
filter.init(null);
try {
filter.attemptAuthentication(request);
fail("Should have thrown AuthenticationException");
} catch (AuthenticationException expected) {
assertTrue(true);
}
}
}
@@ -0,0 +1,71 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* 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 net.sf.acegisecurity.ui.cas;
import junit.framework.TestCase;
/**
* Tests {@link ServiceProperties}.
*
* @author Ben Alex
* @version $Id$
*/
public class ServicePropertiesTests extends TestCase {
//~ Constructors ===========================================================
public ServicePropertiesTests() {
super();
}
public ServicePropertiesTests(String arg0) {
super(arg0);
}
//~ Methods ================================================================
public final void setUp() throws Exception {
super.setUp();
}
public static void main(String[] args) {
junit.textui.TestRunner.run(ServicePropertiesTests.class);
}
public void testDetectsMissingLoginFormUrl() throws Exception {
ServiceProperties sp = new ServiceProperties();
try {
sp.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("service must be specified", expected.getMessage());
}
}
public void testGettersSetters() throws Exception {
ServiceProperties sp = new ServiceProperties();
sp.setSendRenew(false);
assertFalse(sp.isSendRenew());
sp.setSendRenew(true);
assertTrue(sp.isSendRenew());
sp.setService("https://mycompany.com/service");
assertEquals("https://mycompany.com/service", sp.getService());
sp.afterPropertiesSet();
}
}