This site contains the documentation that is relevant to older WSO2 product versions and offerings.
For the latest WSO2 documentation, go to https://wso2.com/documentation/.
Creating Custom Authenticators
In addition to local and federated authenticators, it is possible to create custom authenticators. The following is the API used to configure a custom authenticator.
/* * Copyright (c) 2005-2013, 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.application.authentication.framework; import java.io.Serializable; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext; import org.wso2.carbon.identity.application.authentication.framework.exception.AuthenticationFailedException; import org.wso2.carbon.identity.application.authentication.framework.exception.LogoutFailedException; import org.wso2.carbon.identity.application.common.model.Property; /** * API of the Application Authenticators. * */ public interface ApplicationAuthenticator extends Serializable { /** * Check whether the authentication or logout request can be handled by the * authenticator * * @param request * @return boolean */ public boolean canHandle(HttpServletRequest request); /** * Process the authentication or logout request. * * @param request * @param response * @param context * @return the status of the flow * @throws AuthenticationFailedException * @throws LogoutFailedException */ public AuthenticatorFlowStatus process(HttpServletRequest request, HttpServletResponse response, AuthenticationContext context) throws AuthenticationFailedException, LogoutFailedException; /** * Get the Context identifier sent with the request. This identifier is used * to retrieve the state of the authentication/logout flow * * @param request * @return */ public String getContextIdentifier(HttpServletRequest request); /** * Get the name of the Authenticator * @return name */ public String getName(); /** * @return */ public String getFriendlyName(); /** * Get the claim dialect URI if this authenticator receives claims in a standard dialect * and needs to be mapped to the Carbon dialect http://wso2.org/claims * @return boolean */ public String getClaimDialectURI(); /** * @return */ public List<Property> getConfigurationProperties(); }
This API can be used to configure a custom authenticator. As an example, a Facebook authenticator is configured using the above API.
Configuring a custom authenticator for Facebook
See here for the SVN source code used to develop a sample custom Facebook authenticator.
/* * Copyright (c) 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.application.authenticator.facebook; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.amber.oauth2.client.request.OAuthClientRequest; import org.apache.amber.oauth2.client.response.OAuthAuthzResponse; import org.apache.amber.oauth2.common.exception.OAuthProblemException; import org.apache.amber.oauth2.common.exception.OAuthSystemException; import org.apache.amber.oauth2.common.utils.JSONUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.codehaus.jettison.json.JSONException; import org.wso2.carbon.identity.application.authentication.framework.AbstractApplicationAuthenticator; import org.wso2.carbon.identity.application.authentication.framework.FederatedApplicationAuthenticator; import org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext; import org.wso2.carbon.identity.application.authentication.framework.exception.AuthenticationFailedException; import org.wso2.carbon.ui.CarbonUIUtil; public class FacebookAuthenticator extends AbstractApplicationAuthenticator implements FederatedApplicationAuthenticator { private static final long serialVersionUID = 1L; private static final Log LOGGER = LogFactory.getLog(FacebookAuthenticator.class); @Override public boolean canHandle(HttpServletRequest request) { LOGGER.trace("Inside FacebookAuthenticator.canHandle()"); // Check commonauth got an OIDC response if (request.getParameter(FacebookAuthenticatorConstants.OAUTH2_GRANT_TYPE_CODE) != null && request.getParameter(FacebookAuthenticatorConstants.OAUTH2_PARAM_STATE) != null && FacebookAuthenticatorConstants.FACEBOOK_LOGIN_TYPE.equals(getLoginType(request))) { return true; } return false; } @Override protected void initiateAuthenticationRequest(HttpServletRequest request, HttpServletResponse response, AuthenticationContext context) throws AuthenticationFailedException { try { Map<String,String> authenticatorProperties = context.getAuthenticatorProperties(); String clientId = authenticatorProperties.get(FacebookAuthenticatorConstants.CLIENT_ID); String authorizationEP = FacebookAuthenticatorConstants.FB_AUTHZ_URL; String scope = FacebookAuthenticatorConstants.SCOPE; String callbackurl = CarbonUIUtil.getAdminConsoleURL(request); callbackurl = callbackurl.replace("commonauth/carbon/", "commonauth"); String state = context.getContextIdentifier() + "," + FacebookAuthenticatorConstants.FACEBOOK_LOGIN_TYPE; OAuthClientRequest authzRequest = OAuthClientRequest.authorizationLocation(authorizationEP) .setClientId(clientId) .setRedirectURI(callbackurl) .setResponseType(FacebookAuthenticatorConstants.OAUTH2_GRANT_TYPE_CODE) .setScope(scope).setState(state) .buildQueryMessage(); response.sendRedirect(authzRequest.getLocationUri()); } catch (IOException e) { LOGGER.error("Exception while sending to the login page.", e); throw new AuthenticationFailedException(e.getMessage(), e); } catch (OAuthSystemException e) { LOGGER.error("Exception while building authorization code request.", e); throw new AuthenticationFailedException(e.getMessage(), e); } return; } private String getClientID(Map<String, String> authenticatorProperties, String clientId) { return authenticatorProperties.get(clientId); } @Override protected void processAuthenticationResponse(HttpServletRequest request, HttpServletResponse response, AuthenticationContext context) throws AuthenticationFailedException { LOGGER.trace("Inside FacebookAuthenticator.authenticate()"); try { Map<String,String> authenticatorProperties = context.getAuthenticatorProperties(); String clientId = authenticatorProperties.get(FacebookAuthenticatorConstants.CLIENT_ID); String clientSecret = authenticatorProperties.get(FacebookAuthenticatorConstants.CLIENT_SECRET); String tokenEndPoint = FacebookAuthenticatorConstants.FB_TOKEN_URL; String fbauthUserInfoUrl = FacebookAuthenticatorConstants.FB_USER_INFO_URL; String callbackurl = CarbonUIUtil.getAdminConsoleURL(request); callbackurl = callbackurl.replace("commonauth/carbon/", "commonauth"); String code = getAuthorizationCode(request); String token = getToken(tokenEndPoint, clientId, clientSecret, callbackurl, code); String authenticatedUser = getUserName(fbauthUserInfoUrl, token); context.setSubject(authenticatedUser); } catch (AuthenticatorException e) { LOGGER.error("Failed to process Facebook Connect response.", e); throw new AuthenticationFailedException(e.getMessage(), e); } } private String getAuthorizationCode(HttpServletRequest request) throws AuthenticatorException { OAuthAuthzResponse authzResponse; try { authzResponse = OAuthAuthzResponse.oauthCodeAuthzResponse(request); return authzResponse.getCode(); } catch (OAuthProblemException e) { throw new AuthenticatorException("Exception while reading authorization code.", e); } } private String getToken(String tokenEndPoint, String clientId, String clientSecret, String callbackurl, String code) throws AuthenticatorException { OAuthClientRequest tokenRequest = null; String token = null; try { tokenRequest = buidTokenRequest(tokenEndPoint, clientId, clientSecret, callbackurl, code); token = sendRequest(tokenRequest.getLocationUri()); if (token.startsWith("{")) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Received token: " + token + " for code: " + code); } throw new AuthenticatorException("Received access token is invalid."); } } catch (MalformedURLException e) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("URL : " + tokenRequest.getLocationUri()); } throw new AuthenticatorException( "MalformedURLException while sending access token request.", e); } catch (IOException e) { throw new AuthenticatorException("IOException while sending access token request.", e); } return token; } private OAuthClientRequest buidTokenRequest(String tokenEndPoint, String clientId, String clientSecret, String callbackurl, String code) throws AuthenticatorException { OAuthClientRequest tokenRequest = null; try { tokenRequest = OAuthClientRequest.tokenLocation(tokenEndPoint).setClientId(clientId) .setClientSecret(clientSecret) .setRedirectURI(callbackurl).setCode(code) .buildQueryMessage(); } catch (OAuthSystemException e) { throw new AuthenticatorException("Exception while building access token request.", e); } return tokenRequest; } private String getUserInformation(String fbauthUserInfoUrl, String token) throws AuthenticatorException { String userInfoString = null; try { userInfoString = sendRequest(fbauthUserInfoUrl + "?" + token); } catch (MalformedURLException e) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("URL : " + fbauthUserInfoUrl + token, e); } throw new AuthenticatorException( "MalformedURLException while sending user information request.", e); } catch (IOException e) { throw new AuthenticatorException( "IOException while sending sending user information request.", e); } return userInfoString; } private String getUserName(String fbauthUserInfoUrl, String token) throws AuthenticatorException { String userName = null; String userInfoString = getUserInformation(fbauthUserInfoUrl, token); try { Map<String, Object> jsonObject = JSONUtils.parseJSON(userInfoString); userName = (String) jsonObject.get(FacebookAuthenticatorConstants.USERNAME); } catch (JSONException e) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("UserInfoString : " + userInfoString, e); } throw new AuthenticatorException("Exception while parsing User Information.", e); } return userName; } @Override public String getContextIdentifier(HttpServletRequest request) { LOGGER.trace("Inside FacebookAuthenticator.getContextIdentifier()"); String state = request.getParameter(FacebookAuthenticatorConstants.OAUTH2_PARAM_STATE); if (state != null) { return state.split(",")[0]; } else { return null; } } private String sendRequest(String url) throws IOException { URLConnection urlConnection = new URL(url).openConnection(); BufferedReader in = new BufferedReader( new InputStreamReader(urlConnection.getInputStream())); StringBuilder b = new StringBuilder(); String inputLine = in.readLine(); while (inputLine != null) { b.append(inputLine).append("\n"); inputLine = in.readLine(); } in.close(); return b.toString(); } private String getLoginType(HttpServletRequest request) { String state = request.getParameter(FacebookAuthenticatorConstants.OAUTH2_PARAM_STATE); if (state != null) { return state.split(",")[1]; } else { return null; } } @Override public String getFriendlyName() { return "facebook"; } @Override public String getName() { return FacebookAuthenticatorConstants.AUTHENTICATOR_NAME; } }