/*
* Copyright (c) 2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*
*/
package org.wso2.carbon.identity.sso.agent.openid;
import org.apache.commons.collections.MapUtils;
import org.openid4java.association.AssociationException;
import org.openid4java.consumer.ConsumerException;
import org.openid4java.consumer.ConsumerManager;
import org.openid4java.consumer.VerificationResult;
import org.openid4java.discovery.Discovery;
import org.openid4java.discovery.DiscoveryException;
import org.openid4java.discovery.DiscoveryInformation;
import org.openid4java.discovery.Identifier;
import org.openid4java.discovery.yadis.YadisException;
import org.openid4java.discovery.yadis.YadisResolver;
import org.openid4java.message.AuthRequest;
import org.openid4java.message.AuthSuccess;
import org.openid4java.message.MessageException;
import org.openid4java.message.ParameterList;
import org.openid4java.message.ax.AxMessage;
import org.openid4java.message.ax.FetchRequest;
import org.openid4java.message.ax.FetchResponse;
import org.openid4java.server.RealmVerifierFactory;
import org.openid4java.util.HttpFetcherFactory;
import org.wso2.carbon.identity.sso.agent.SSOAgentConstants;
import org.wso2.carbon.identity.sso.agent.SSOAgentDataHolder;
import org.wso2.carbon.identity.sso.agent.SSOAgentException;
import org.wso2.carbon.identity.sso.agent.bean.LoggedInSessionBean;
import org.wso2.carbon.identity.sso.agent.bean.SSOAgentConfig;
import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class OpenIDManager {
// Smart OpenID Consumer Manager
AttributesRequestor attributesRequestor = null;
private SSOAgentConfig ssoAgentConfig = null;
public OpenIDManager(SSOAgentConfig ssoAgentConfig) throws SSOAgentException {
SSOAgentDataHolder.getInstance().setConsumerManager(getConsumerManagerInstance());
this.ssoAgentConfig = ssoAgentConfig;
}
private ConsumerManager getConsumerManagerInstance() throws SSOAgentException {
HttpFetcherFactory httpFetcherFactory = null;
try {
httpFetcherFactory = new HttpFetcherFactory(SSLContext.getDefault(), null);
} catch (NoSuchAlgorithmException e) {
throw new SSOAgentException("Error while getting default SSL Context", e);
}
return new ConsumerManager(
new RealmVerifierFactory(new YadisResolver(httpFetcherFactory)),
new Discovery(), httpFetcherFactory);
}
public String doOpenIDLogin(HttpServletRequest request, HttpServletResponse response) throws SSOAgentException {
String claimedId = ssoAgentConfig.getOpenId().getClaimedId();
try {
ConsumerManager manager = SSOAgentDataHolder.getInstance().getConsumerManager();
if (ssoAgentConfig.getOpenId().isDumbModeEnabled()) {
// Switch the consumer manager to dumb mode
manager.setMaxAssocAttempts(0);
}
// Discovery on the user supplied ID
List discoveries = manager.discover(claimedId);
// Associate with the OP and share a secret
DiscoveryInformation discovered = manager.associate(discoveries);
// Keeping necessary parameters to verify the AuthResponse
LoggedInSessionBean sessionBean = new LoggedInSessionBean();
sessionBean.setOpenId(sessionBean.new OpenID());
sessionBean.getOpenId().setDiscoveryInformation(discovered); // set the discovery information
request.getSession().setAttribute(SSOAgentConstants.SESSION_BEAN_NAME, sessionBean);
manager.setImmediateAuth(true);
AuthRequest authReq = manager.authenticate(discovered,
ssoAgentConfig.getOpenId().getReturnToURL());
// Request subject attributes using Attribute Exchange extension specification if AttributeExchange is enabled
if (ssoAgentConfig.getOpenId().isAttributeExchangeEnabled() &&
ssoAgentConfig.getOpenId().getAttributesRequestor() != null) {
attributesRequestor = ssoAgentConfig.getOpenId().getAttributesRequestor();
attributesRequestor.init();
String[] requestedAttributes = attributesRequestor.getRequestedAttributes(claimedId);
// Getting required attributes using FetchRequest
FetchRequest fetchRequest = FetchRequest.createFetchRequest();
for (String requestedAttribute : requestedAttributes) {
fetchRequest.addAttribute(requestedAttribute,
attributesRequestor.getTypeURI(claimedId, requestedAttribute),
attributesRequestor.isRequired(claimedId, requestedAttribute),
attributesRequestor.getCount(claimedId, requestedAttribute));
}
// Adding the AX extension to the AuthRequest message
authReq.addExtension(fetchRequest);
}
// Returning OP Url
SSOAgentDataHolder.getInstance().setConsumerManager(manager);
StringBuilder destinationUrl = new StringBuilder(authReq.getDestinationUrl(true));
if (MapUtils.isNotEmpty(ssoAgentConfig.getQueryParams())) {
StringBuilder builder = new StringBuilder();
for (Map.Entry<String, String[]> entry : ssoAgentConfig.getQueryParams().entrySet()) {
if (entry.getKey() != null && entry.getValue() != null && entry.getValue().length > 0) {
for (String param : entry.getValue()) {
builder.append("&").append(entry.getKey()).append("=").append(param);
}
}
}
destinationUrl.append(builder);
}
return destinationUrl.toString();
} catch (YadisException e) {
if (e.getErrorCode() == 1796) {
throw new SSOAgentException(e.getMessage(), e);
}
throw new SSOAgentException("Error while creating FetchRequest", e);
} catch (MessageException e) {
throw new SSOAgentException("Error while creating FetchRequest", e);
} catch (DiscoveryException e) {
throw new SSOAgentException("Error while doing OpenID Discovery", e);
} catch (ConsumerException e) {
throw new SSOAgentException("Error while doing OpenID Authentication", e);
}
}
public void processOpenIDLoginResponse(HttpServletRequest request, HttpServletResponse response) throws SSOAgentException {
try {
// Getting all parameters in request including AuthResponse
ParameterList authResponseParams = new ParameterList(request.getParameterMap());
// Get previously saved session bean
LoggedInSessionBean loggedInSessionBean = (LoggedInSessionBean) request.getSession(false).
getAttribute(SSOAgentConstants.SESSION_BEAN_NAME);
if (loggedInSessionBean == null) {
throw new SSOAgentException("Error while verifying OpenID response. " +
"Cannot find valid session for user");
}
// Previously discovered information
DiscoveryInformation discovered = loggedInSessionBean.getOpenId().getDiscoveryInformation();
// Verify return-to, discoveries, nonce & signature
// Signature will be verified using the shared secret
VerificationResult verificationResult = SSOAgentDataHolder.getInstance().getConsumerManager().verify(
ssoAgentConfig.getOpenId().getReturnToURL(), authResponseParams, discovered);
Identifier verified = verificationResult.getVerifiedId();
// Identifier will be NULL if verification failed
if (verified != null) {
AuthSuccess authSuccess = (AuthSuccess) verificationResult.getAuthResponse();
loggedInSessionBean.getOpenId().setClaimedId(authSuccess.getIdentity());
// Get requested attributes using AX extension
if (authSuccess.hasExtension(AxMessage.OPENID_NS_AX)) {
Map<String, List<String>> attributesMap = new HashMap<String, List<String>>();
if (ssoAgentConfig.getOpenId().getAttributesRequestor() != null) {
attributesRequestor = ssoAgentConfig.getOpenId().getAttributesRequestor();
String[] attrArray = attributesRequestor.getRequestedAttributes(authSuccess.getIdentity());
FetchResponse fetchResp = (FetchResponse) authSuccess.getExtension(AxMessage.OPENID_NS_AX);
for (String attr : attrArray) {
List attributeValues = fetchResp.getAttributeValuesByTypeUri(attributesRequestor.getTypeURI(authSuccess.getIdentity(), attr));
if (attributeValues.get(0) instanceof String && ((String) attributeValues.get(0)).split(",").length > 1) {
String[] splitString = ((String) attributeValues.get(0)).split(",");
for (String part : splitString) {
attributeValues.add(part);
}
}
if (attributeValues.get(0) != null) {
attributesMap.put(attr, attributeValues);
}
}
}
loggedInSessionBean.getOpenId().setSubjectAttributes(attributesMap);
}
} else {
throw new SSOAgentException("OpenID verification failed");
}
} catch (AssociationException e) {
throw new SSOAgentException("Error while verifying OpenID response", e);
} catch (MessageException e) {
throw new SSOAgentException("Error while verifying OpenID response", e);
} catch (DiscoveryException e) {
throw new SSOAgentException("Error while verifying OpenID response", e);
}
}
}