This site contains the documentation that is relevant to older WSO2 product versions and offerings.
For the latest WSO2 documentation, visit 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;
}
}
, multiple selections available,