/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* 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 org.wso2.carbon.identity.application.authenticator.social.yahoo;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.oltu.oauth2.client.response.OAuthClientResponse;
import org.apache.oltu.oauth2.common.utils.JSONUtils;
import org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext;
import org.wso2.carbon.identity.application.authenticator.oidc.OIDCAuthenticatorConstants;
import org.wso2.carbon.identity.application.authenticator.oidc.OpenIDConnectAuthenticator;
import org.wso2.carbon.identity.application.common.model.ClaimMapping;
import org.wso2.carbon.identity.application.common.model.Property;
import org.wso2.carbon.identity.application.common.util.IdentityApplicationConstants;
import org.wso2.carbon.identity.base.IdentityConstants;
import org.wso2.carbon.identity.core.util.IdentityUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* OAuth 2.0 Authenticator for Yahoo.
*/
public class YahooOAuth2Authenticator extends OpenIDConnectAuthenticator {
private static Log log = LogFactory.getLog(YahooOAuth2Authenticator.class);
private static final long serialVersionUID = -4290245763061524219L;
private String oAuthEndpoint;
private String tokenEndpoint;
private String userInfoURL;
/**
* Initialize the Yahoo OAuth endpoint url.
*/
private void initOAuthEndpoint() {
oAuthEndpoint = getAuthenticatorConfig().getParameterMap()
.get(YahooOAuth2AuthenticatorConstants.YAHOO_OAUTHZ_ENDPOINT);
if (oAuthEndpoint == null) {
oAuthEndpoint = IdentityApplicationConstants.YAHOO_OAUTH2_URL;
}
}
/**
* Initialize the Yahoo token endpoint url.
*/
private void initTokenEndpoint() {
tokenEndpoint = getAuthenticatorConfig().getParameterMap()
.get(YahooOAuth2AuthenticatorConstants.YAHOO_TOKEN_ENDPOINT);
if (tokenEndpoint == null) {
tokenEndpoint = IdentityApplicationConstants.YAHOO_TOKEN_URL;
}
}
/**
* Initialize the Yahoo user info url.
*/
private void initUserInfoURL() {
userInfoURL = getAuthenticatorConfig().getParameterMap()
.get(YahooOAuth2AuthenticatorConstants.YAHOO_USERINFO_ENDPOINT);
if (userInfoURL == null) {
userInfoURL = IdentityApplicationConstants.YAHOO_USERINFO_URL;
}
}
/**
* Get authorization server endpoint.
*
* @param authenticatorProperties Authenticator properties.
* @return OAuth2 Endpoint
*/
@Override
protected String getAuthorizationServerEndpoint(Map<String, String> authenticatorProperties) {
if (oAuthEndpoint == null) {
initOAuthEndpoint();
}
return oAuthEndpoint;
}
/**
* Get token access endpoint.
*
* @param authenticatorProperties Authenticator properties.
* @return Token endpoint
*/
@Override
protected String getTokenEndpoint(Map<String, String> authenticatorProperties) {
if (tokenEndpoint == null) {
initTokenEndpoint();
}
return tokenEndpoint;
}
/**
* Get the default claim dialect URI.
*
* @return Claim dialect URI.
*/
@Override
public String getClaimDialectURI() {
// We do not have a default claim dialect.
return null;
}
/**
* Get the user info endpoint url.
*
* @return User info endpoint url.
*/
private String getUserInfoURL() {
if (userInfoURL == null) {
initUserInfoURL();
}
return userInfoURL;
}
/**
* Get OAuth2 Scope
*
* @param scope Scope
* @param authenticatorProperties Authentication properties.
* @return OAuth2 Scope
*/
@Override
protected String getScope(String scope, Map<String, String> authenticatorProperties) {
return YahooOAuth2AuthenticatorConstants.YAHOO_SCOPE;
}
/**
* Get Authenticated User
*
* @param token OAuth client response.
* @return GUID of the authenticated user.
*/
@Override
protected String getAuthenticateUser(AuthenticationContext context, Map<String, Object> jsonObject, OAuthClientResponse token) {
return token.getParam(YahooOAuth2AuthenticatorConstants.USER_GUID);
}
/**
* Get the user info endpoint.
*
* @param token OAuth client response.
* @return User info endpoint.
*/
@Override
protected String getUserInfoEndpoint(OAuthClientResponse token, Map<String, String> authenticatorProperties) {
String userGUID = token.getParam(YahooOAuth2AuthenticatorConstants.USER_GUID);
return getUserInfoURL() + userGUID + YahooOAuth2AuthenticatorConstants.YAHOO_USER_DETAILS_JSON;
}
/**
* Get Friendly Name.
*
* @return Friendly name.
*/
@Override
public String getFriendlyName() {
return YahooOAuth2AuthenticatorConstants.YAHOO_CONNECTOR_FRIENDLY_NAME;
}
/**
* Get connector name.
*
* @return Connector name.
*/
@Override
public String getName() {
return YahooOAuth2AuthenticatorConstants.YAHOO_CONNECTOR_NAME;
}
/**
* Always return false as there is no ID token in Yahoo OAuth.
*
* @param authenticatorProperties Authenticator properties.
* @return False
*/
@Override
protected boolean requiredIDToken(Map<String, String> authenticatorProperties) {
return false;
}
/**
* Get subject attributes.
*
* @param token OAuthClientResponse
* @param authenticatorProperties Map<String, String>
* @return Map<ClaimMapping, String> Claim mappings.
*/
protected Map<ClaimMapping, String> getSubjectAttributes(OAuthClientResponse token,
Map<String, String> authenticatorProperties) {
Map<ClaimMapping, String> claims = new HashMap<>();
try {
String accessToken = token.getParam(OIDCAuthenticatorConstants.ACCESS_TOKEN);
String url = getUserInfoEndpoint(token, authenticatorProperties);
String json = sendRequest(url, accessToken);
if (StringUtils.isBlank(json)) {
if (log.isDebugEnabled()) {
log.debug("Unable to fetch user claims. Proceeding without user claims");
}
return claims;
}
Map<String, Object> jsonObject = JSONUtils.parseJSON(json);
Map<String, Object> profile = null;
if (!jsonObject.isEmpty()) {
// Extract the inner profile JSON object.
profile = JSONUtils.parseJSON(jsonObject.entrySet().iterator().next().getValue().toString());
}
if (profile == null) {
if (log.isDebugEnabled()) {
log.debug("Invalid user profile object. Proceeding without user claims");
}
return claims;
}
for (Map.Entry<String, Object> data : profile.entrySet()) {
String key = data.getKey();
claims.put(ClaimMapping.build(key, key, null, false), profile.get(key).toString());
if (log.isDebugEnabled()
&& IdentityUtil.isTokenLoggable(IdentityConstants.IdentityTokens.USER_CLAIMS)) {
log.debug("Adding claims from end-point data mapping : " + key + " - " +
profile.get(key).toString());
}
}
} catch (IOException e) {
log.error("Communication error occurred while accessing user info endpoint", e);
}
return claims;
}
/**
* Get configuration properties.
*
* @return Properties list.
*/
@Override
public List<Property> getConfigurationProperties() {
List<Property> configProperties = new ArrayList<>();
Property clientId = new Property();
clientId.setName(OIDCAuthenticatorConstants.CLIENT_ID);
clientId.setDisplayName("Client Id");
clientId.setRequired(true);
clientId.setDescription("Enter Yahoo IDP client identifier value");
clientId.setDisplayOrder(1);
configProperties.add(clientId);
Property clientSecret = new Property();
clientSecret.setName(OIDCAuthenticatorConstants.CLIENT_SECRET);
clientSecret.setDisplayName("Client Secret");
clientSecret.setRequired(true);
clientSecret.setConfidential(true);
clientSecret.setDescription("Enter Yahoo IDP client secret value");
clientSecret.setDisplayOrder(2);
configProperties.add(clientSecret);
Property callbackUrl = new Property();
callbackUrl.setDisplayName("Callback URL");
callbackUrl.setName(IdentityApplicationConstants.OAuth2.CALLBACK_URL);
callbackUrl.setDescription("Enter value corresponding to callback url.");
callbackUrl.setDisplayOrder(3);
configProperties.add(callbackUrl);
return configProperties;
}
}