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:
@@ -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);
|
||||
}
|
||||
|
||||
+42
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user