Java tutorial
/* * Copyright (c) 2015, 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.authenticator.smsotp; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; 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.LocalApplicationAuthenticator; 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.model.AuthenticatedUser; import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils; import org.wso2.carbon.identity.application.authentication.framework.config.ConfigurationFacade; import org.wso2.carbon.identity.application.common.model.Property; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.user.core.UserRealm; import org.wso2.carbon.user.core.UserStoreException; import org.wso2.carbon.user.core.service.RealmService; import org.wso2.carbon.utils.multitenancy.MultitenantUtils; import javax.net.ssl.HttpsURLConnection; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.lang.System; import java.net.MalformedURLException; import java.net.ProtocolException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; /** * Authenticator of SMSOTP */ public class SMSOTPAuthenticator extends AbstractApplicationAuthenticator implements FederatedApplicationAuthenticator { private static Log log = LogFactory.getLog(SMSOTPAuthenticator.class); Map<String, String> newAuthenticatorProperties; private String otpToken; private String mobile = ""; private String smsUrl = ""; private String clientId = ""; private String clientSecret = ""; private String fullUrl = ""; /** * Check whether the authentication or logout request can be handled by the authenticator */ public boolean canHandle(HttpServletRequest request) { if (log.isDebugEnabled()) { log.debug("Inside SMSOTPAuthenticator canHandle method"); } return StringUtils.isNotEmpty(request.getParameter(SMSOTPConstants.CODE)); } /** * initiate the authentication request */ @Override protected void initiateAuthenticationRequest(HttpServletRequest request, HttpServletResponse response, AuthenticationContext context) throws AuthenticationFailedException { String resourceName = SMSOTPConstants.PROPERTIES_FILE; ClassLoader loader = Thread.currentThread().getContextClassLoader(); Properties prop = new Properties(); InputStream resourceStream = loader.getResourceAsStream(resourceName); try { prop.load(resourceStream); } catch (IOException e) { throw new AuthenticationFailedException("Can not find the file", e); } newAuthenticatorProperties = context.getAuthenticatorProperties(); newAuthenticatorProperties.put("username", prop.getProperty("username")); newAuthenticatorProperties.put("password", prop.getProperty("password")); newAuthenticatorProperties.put("from", prop.getProperty("from")); newAuthenticatorProperties.put("text", prop.getProperty("text")); context.setAuthenticatorProperties(newAuthenticatorProperties); OneTimePassword token = new OneTimePassword(); String secret = OneTimePassword.getRandomNumber(SMSOTPConstants.SECRET_KEY_LENGTH); otpToken = token.generateToken(secret, "" + SMSOTPConstants.NUMBER_BASE, SMSOTPConstants.NUMBER_DIGIT); Object myToken = SMSOTPConstants.OTP_TOKEN; context.setProperty(SMSOTPConstants.OTP_TOKEN, myToken); Map<String, String> authenticatorProperties = context.getAuthenticatorProperties(); clientId = authenticatorProperties.get(SMSOTPConstants.API_KEY); clientSecret = authenticatorProperties.get(SMSOTPConstants.API_SECRET); smsUrl = authenticatorProperties.get(SMSOTPConstants.SMS_URL); String loginPage = ConfigurationFacade.getInstance().getAuthenticationEndpointURL() .replace("authenticationendpoint/login.do", SMSOTPConstants.LOGIN_PAGE); String queryParams = FrameworkUtils.getQueryStringWithFrameworkContextId(context.getQueryParams(), context.getCallerSessionKey(), context.getContextIdentifier()); String retryParam = ""; if (context.isRetrying()) { retryParam = SMSOTPConstants.RETRY_PARAMS; } try { response.sendRedirect(response.encodeRedirectURL(loginPage + ("?" + queryParams)) + "&authenticators=" + getName() + retryParam); } catch (IOException e) { log.error("Authentication failed!", e); throw new AuthenticationFailedException(e.getMessage(), e); } String username = null; for (Integer stepMap : context.getSequenceConfig().getStepMap().keySet()) if (context.getSequenceConfig().getStepMap().get(stepMap).getAuthenticatedUser() != null && context.getSequenceConfig().getStepMap().get(stepMap).getAuthenticatedAutenticator() .getApplicationAuthenticator() instanceof LocalApplicationAuthenticator) { username = String .valueOf(context.getSequenceConfig().getStepMap().get(stepMap).getAuthenticatedUser()); break; } if (StringUtils.isNotEmpty(username)) { UserRealm userRealm = null; try { String tenantDomain = MultitenantUtils.getTenantDomain(username); int tenantId = IdentityTenantUtil.getTenantId(tenantDomain); RealmService realmService = IdentityTenantUtil.getRealmService(); userRealm = (UserRealm) realmService.getTenantUserRealm(tenantId); } catch (Exception e) { throw new AuthenticationFailedException("Cannot find the user realm", e); } username = MultitenantUtils.getTenantAwareUsername(String.valueOf(username)); if (userRealm != null) { try { mobile = userRealm.getUserStoreManager() .getUserClaimValue(username, SMSOTPConstants.MOBILE_CLAIM, null).toString(); } catch (UserStoreException e) { log.error("Cannot find the user claim for mobile", e); throw new AuthenticationFailedException( "Cannot find the user claim for mobile " + e.getMessage(), e); } } } if (StringUtils.isNotEmpty(clientId) && StringUtils.isNotEmpty(clientSecret) && StringUtils.isNotEmpty(mobile)) { fullUrl = setUrl(); try { if (!sendRESTCall(smsUrl, fullUrl)) { log.error("Unable to send the code"); throw new AuthenticationFailedException("Unable to send the code"); } } catch (IOException e) { if (log.isDebugEnabled()) { log.debug("Error while sending the HTTP request", e); } } } } /** * Process the response of the SMSOTP end-point */ @Override protected void processAuthenticationResponse(HttpServletRequest request, HttpServletResponse response, AuthenticationContext context) throws AuthenticationFailedException { String userToken = request.getParameter(SMSOTPConstants.CODE); String contextToken = (String) context.getProperty(SMSOTPConstants.OTP_TOKEN); if (userToken.equals(contextToken)) { context.setSubject( AuthenticatedUser.createLocalAuthenticatedUserFromSubjectIdentifier("an authorised user")); } else { log.error("Code Mismatch"); throw new AuthenticationFailedException("Code mismatch"); } } /** * Get the friendly name of the Authenticator */ public String getFriendlyName() { return SMSOTPConstants.AUTHENTICATOR_FRIENDLY_NAME; } /** * Get the name of the Authenticator */ public String getName() { return SMSOTPConstants.AUTHENTICATOR_NAME; } /** * Get the Context identifier sent with the request. */ public String getContextIdentifier(HttpServletRequest httpServletRequest) { return null; } /** * Get the configuration properties of UI */ @Override public List<Property> getConfigurationProperties() { List<Property> configProperties = new ArrayList<Property>(); Property clientId = new Property(); clientId.setName(SMSOTPConstants.API_KEY); clientId.setDisplayName("API Id"); clientId.setRequired(true); clientId.setDescription("Enter client identifier value"); configProperties.add(clientId); Property smsUrl = new Property(); smsUrl.setName(SMSOTPConstants.SMS_URL); smsUrl.setDisplayName("SMS URL"); smsUrl.setRequired(true); smsUrl.setDescription("Enter client sms url value"); configProperties.add(smsUrl); Property clientSecret = new Property(); clientSecret.setName(SMSOTPConstants.API_SECRET); clientSecret.setDisplayName("API Secret"); clientSecret.setRequired(true); clientSecret.setConfidential(true); clientSecret.setDescription("Enter client secret value"); configProperties.add(clientSecret); return configProperties; } /** * Send REST call */ public boolean sendRESTCall(String url, String urlParameters) throws IOException { HttpsURLConnection connection = null; try { URL smsProviderUrl = new URL(url + urlParameters); connection = (HttpsURLConnection) smsProviderUrl.openConnection(); connection.setDoInput(true); connection.setDoOutput(true); connection.setRequestMethod(SMSOTPConstants.HTTP_METHOD); if (connection.getResponseCode() == 200) { if (log.isDebugEnabled()) { log.debug("Code is successfully sent to your mobile number"); } return true; } connection.disconnect(); } catch (MalformedURLException e) { if (log.isDebugEnabled()) { log.error("Invalid URL", e); } throw new MalformedURLException(); } catch (ProtocolException e) { if (log.isDebugEnabled()) { log.error("Error while setting the HTTP method", e); } throw new ProtocolException(); } catch (IOException e) { if (log.isDebugEnabled()) { log.error("Error while getting the HTTP response", e); } throw new IOException(); } finally { connection.disconnect(); } return false; } public String setUrl() { fullUrl = newAuthenticatorProperties.get("username") + clientId + newAuthenticatorProperties.get("password") + clientSecret + newAuthenticatorProperties.get("from") + mobile + newAuthenticatorProperties.get("text") + otpToken; return fullUrl; } }