1
0
mirror of synced 2026-05-22 21:33:16 +00:00

SEC-1460: Added AxFetchListFactory which matches OpenID identifiers to lists of attributes to use in a fetch-request.

This allows different configurations to be used based on the identity-provider (google, yahoo etc). The default implementation iterates through a map of regex patterns to attribute lists. The namespace has also been extended to support this facility, with the "identifier-match" attribute being added to the attribute-exchange element. Multiple attribute-exchange elements can now be defined, each matching a different identifier.
This commit is contained in:
Luke Taylor
2010-04-20 23:44:58 +01:00
parent 3af75afec1
commit 2f025fba6c
9 changed files with 211 additions and 44 deletions
@@ -0,0 +1,25 @@
package org.springframework.security.openid;
import java.util.List;
/**
* A strategy which can be used by an OpenID consumer implementation, to dynamically determine
* the attribute exchange information based on the OpenID identifier.
* <p>
* This allows the list of attributes for a fetch request to be tailored for different OpenID providers, since they
* do not all support the same attributes.
*
* @author Luke Taylor
* @since 3.1
*/
public interface AxFetchListFactory {
/**
* Builds the list of attributes which should be added to the fetch request for the
* supplied OpenID identifier.
*
* @param identifier the claimed_identity
* @return the attributes to fetch for this identifier
*/
List<OpenIDAttribute> createAttributeList(String identifier);
}
@@ -0,0 +1,14 @@
package org.springframework.security.openid;
import java.util.Collections;
import java.util.List;
/**
* @author Luke Taylor
* @since 3.1
*/
public class NullAxFetchListFactory implements AxFetchListFactory {
public List<OpenIDAttribute> createAttributeList(String identifier) {
return Collections.emptyList();
}
}
@@ -41,31 +41,50 @@ import org.openid4java.message.ax.FetchResponse;
/**
* @author Ray Krueger
* @author Luke Taylor
*/
public class OpenID4JavaConsumer implements OpenIDConsumer {
private static final String DISCOVERY_INFO_KEY = DiscoveryInformation.class.getName();
private static final String ATTRIBUTE_LIST_KEY = "SPRING_SECURITY_OPEN_ID_ATTRIBUTES_FETCH_LIST";
//~ Instance fields ================================================================================================
protected final Log logger = LogFactory.getLog(getClass());
private final ConsumerManager consumerManager;
private List<OpenIDAttribute> attributesToFetch = Collections.emptyList();
private final AxFetchListFactory attributesToFetchFactory;
//~ Constructors ===================================================================================================
public OpenID4JavaConsumer() throws ConsumerException {
this.consumerManager = new ConsumerManager();
this.attributesToFetchFactory = new NullAxFetchListFactory();
}
/**
* @deprecated use the {@link AxFetchListFactory} version instead.
*/
@Deprecated
public OpenID4JavaConsumer(List<OpenIDAttribute> attributes) throws ConsumerException {
this(new ConsumerManager(), attributes);
}
public OpenID4JavaConsumer(ConsumerManager consumerManager, List<OpenIDAttribute> attributes)
@Deprecated
public OpenID4JavaConsumer(ConsumerManager consumerManager, final List<OpenIDAttribute> attributes)
throws ConsumerException {
this.consumerManager = consumerManager;
this.attributesToFetch = Collections.unmodifiableList(attributes);
this.attributesToFetchFactory = new AxFetchListFactory() {
private List<OpenIDAttribute> fetchAttrs = Collections.unmodifiableList(attributes);
public List<OpenIDAttribute> createAttributeList(String identifier) {
return fetchAttrs;
}
};
}
public OpenID4JavaConsumer(AxFetchListFactory attributesToFetchFactory) throws ConsumerException {
this.consumerManager = new ConsumerManager();
this.attributesToFetchFactory = attributesToFetchFactory;
}
//~ Methods ========================================================================================================
@@ -88,9 +107,18 @@ public class OpenID4JavaConsumer implements OpenIDConsumer {
try {
authReq = consumerManager.authenticate(information, returnToUrl, realm);
logger.debug("Looking up attribute fetch list for identifier: " + identityUrl);
List<OpenIDAttribute> attributesToFetch = attributesToFetchFactory.createAttributeList(identityUrl);
if (!attributesToFetch.isEmpty()) {
req.getSession().setAttribute(ATTRIBUTE_LIST_KEY, attributesToFetch);
FetchRequest fetchRequest = FetchRequest.createFetchRequest();
for (OpenIDAttribute attr : attributesToFetch) {
if (logger.isDebugEnabled()) {
logger.debug("Adding attribute " + attr.getType() + " to fetch request");
}
fetchRequest.addAttribute(attr.getName(), attr.getType(), attr.isRequired(), attr.getCount());
}
authReq.addExtension(fetchRequest);
@@ -113,7 +141,10 @@ public class OpenID4JavaConsumer implements OpenIDConsumer {
// retrieve the previously stored discovery information
DiscoveryInformation discovered = (DiscoveryInformation) request.getSession().getAttribute(DISCOVERY_INFO_KEY);
List<OpenIDAttribute> attributesToFetch = (List<OpenIDAttribute>) request.getSession().getAttribute(ATTRIBUTE_LIST_KEY);
request.getSession().removeAttribute(DISCOVERY_INFO_KEY);
request.getSession().removeAttribute(ATTRIBUTE_LIST_KEY);
// extract the receiving URL from the HTTP request
StringBuffer receivingURL = request.getRequestURL();
@@ -136,9 +167,20 @@ public class OpenID4JavaConsumer implements OpenIDConsumer {
throw new OpenIDConsumerException("Error verifying openid response", e);
}
List<OpenIDAttribute> attributes = new ArrayList<OpenIDAttribute>();
// examine the verification result and extract the verified identifier
Identifier verified = verification.getVerifiedId();
if (verified == null) {
Identifier id = discovered.getClaimedIdentifier();
return new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.FAILURE,
id == null ? "Unknown" : id.getIdentifier(),
"Verification status message: [" + verification.getStatusMsg() + "]", attributes);
}
// fetch the attributesToFetch of the response
Message authSuccess = verification.getAuthResponse();
List<OpenIDAttribute> attributes = new ArrayList<OpenIDAttribute>(this.attributesToFetch.size());
if (authSuccess.hasExtension(AxMessage.OPENID_NS_AX)) {
if (debug) {
@@ -166,16 +208,6 @@ public class OpenID4JavaConsumer implements OpenIDConsumer {
}
}
// examine the verification result and extract the verified identifier
Identifier verified = verification.getVerifiedId();
if (verified == null) {
Identifier id = discovered.getClaimedIdentifier();
return new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.FAILURE,
id == null ? "Unknown" : id.getIdentifier(),
"Verification status message: [" + verification.getStatusMsg() + "]", attributes);
}
return new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.SUCCESS, verified.getIdentifier(),
"some message", attributes);
}
@@ -0,0 +1,42 @@
package org.springframework.security.openid;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
/**
*
* @author Luke Taylor
* @since 3.1
*/
public class RegexBasedAxFetchListFactory implements AxFetchListFactory {
private final Map<Pattern, List<OpenIDAttribute>> idToAttributes;
/**
* @param regexMap map of regular-expressions (matching the identifier) to attributes which should be fetched for
* that pattern.
*/
public RegexBasedAxFetchListFactory(Map<String, List<OpenIDAttribute>> regexMap) {
idToAttributes = new LinkedHashMap<Pattern, List<OpenIDAttribute>>();
for (Map.Entry<String, List<OpenIDAttribute>> entry : regexMap.entrySet()) {
idToAttributes.put(Pattern.compile(entry.getKey()), entry.getValue());
}
}
/**
* Iterates through the patterns stored in the map and returns the list of attributes defined for the
* first match. If no match is found, returns an empty list.
*/
public List<OpenIDAttribute> createAttributeList(String identifier) {
for (Map.Entry<Pattern, List<OpenIDAttribute>> entry : idToAttributes.entrySet()) {
if (entry.getKey().matcher(identifier).matches()) {
return entry.getValue();
}
}
return Collections.emptyList();
}
}