AbstractOpenAMAuthenticator.java revision 073875d677d0cc89aa2cc1187c975225a2ead9d3
0N/A/*
0N/A * DO NOT REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0N/A *
0N/A * Copyright (c) 2012-2013 ForgeRock Inc. All rights reserved.
0N/A *
0N/A * The contents of this file are subject to the terms
0N/A * of the Common Development and Distribution License
0N/A * (the License). You may not use this file except in
0N/A * compliance with the License.
0N/A *
0N/A * You can obtain a copy of the License at
0N/A * http://forgerock.org/license/CDDLv1.0.html
0N/A * See the License for the specific language governing
0N/A * permission and limitations under the License.
0N/A *
0N/A * When distributing Covered Code, include this CDDL
0N/A * Header Notice in each file and include the License file
0N/A * at http://forgerock.org/license/CDDLv1.0.html
0N/A * If applicable, add the following below the CDDL Header,
0N/A * with the fields enclosed by brackets [] replaced by
0N/A * your own identifying information:
0N/A * "Portions copyright [year] [name of copyright owner]"
0N/A */
0N/A
0N/Apackage org.forgerock.restlet.ext.openam.server;
0N/A
0N/Aimport org.forgerock.openam.oauth2.OAuth2Constants;
0N/Aimport org.forgerock.openam.oauth2.exceptions.OAuthProblemException;
0N/Aimport org.forgerock.openam.oauth2.provider.impl.OpenAMUser;
0N/Aimport org.forgerock.openam.oauth2.OAuth2Utils;
0N/Aimport org.forgerock.restlet.ext.openam.OpenAMParameters;
0N/Aimport org.restlet.Context;
0N/Aimport org.restlet.Request;
0N/Aimport org.restlet.Response;
0N/Aimport org.restlet.data.Reference;
0N/Aimport org.restlet.data.Status;
0N/Aimport org.restlet.ext.servlet.ServletUtils;
0N/Aimport org.restlet.resource.ResourceException;
0N/Aimport org.restlet.routing.Redirector;
0N/Aimport org.restlet.security.Authenticator;
0N/Aimport org.restlet.security.Enroler;
0N/A
0N/Aimport com.iplanet.sso.SSOException;
0N/Aimport com.iplanet.sso.SSOToken;
0N/Aimport com.sun.identity.idm.AMIdentity;
0N/Aimport com.sun.identity.idm.IdRepoException;
0N/Aimport com.sun.identity.idm.IdUtils;
0N/A
0N/Aimport javax.servlet.http.HttpServletRequest;
0N/Aimport java.net.URI;
0N/Aimport java.net.URISyntaxException;
0N/Aimport java.util.Arrays;
0N/Aimport java.util.HashSet;
0N/Aimport java.util.Set;
0N/A
0N/A/**
0N/A * Used to authenticate to OpenAM and redirect to its login page.
0N/A */
0N/Apublic abstract class AbstractOpenAMAuthenticator extends Authenticator {
0N/A
0N/A private final Reference openamServer;
0N/A private String serviceName = null;
0N/A private String moduleName = null;
0N/A private String realm = null;
0N/A private String locale = null;
0N/A
0N/A //ensure the prompt for login shows the login page atleast one time
0N/A static private boolean hasRan = false;
0N/A
0N/A /**
0N/A * {@inheritDoc}
0N/A */
0N/A public AbstractOpenAMAuthenticator(Context context, OpenAMParameters parameters) {
0N/A super(context);
0N/A this.openamServer = parameters.getOpenAMServerRef();
0N/A init(parameters);
0N/A }
0N/A
0N/A /**
0N/A * {@inheritDoc}
0N/A */
0N/A public AbstractOpenAMAuthenticator(Context context, OpenAMParameters parameters,
0N/A boolean optional) {
0N/A super(context, optional);
0N/A this.openamServer = parameters.getOpenAMServerRef();
0N/A init(parameters);
0N/A }
0N/A
0N/A /**
0N/A * {@inheritDoc}
0N/A */
0N/A public AbstractOpenAMAuthenticator(Context context, OpenAMParameters parameters,
0N/A boolean multiAuthenticating, boolean optional, Enroler enroler) {
0N/A super(context, multiAuthenticating, optional, enroler);
0N/A this.openamServer = parameters.getOpenAMServerRef();
0N/A init(parameters);
0N/A }
0N/A
0N/A /**
0N/A * {@inheritDoc}
0N/A */
0N/A public AbstractOpenAMAuthenticator(Context context, OpenAMParameters parameters,
0N/A boolean optional, Enroler enroler) {
0N/A super(context, optional, enroler);
0N/A this.openamServer = parameters.getOpenAMServerRef();
0N/A init(parameters);
0N/A }
0N/A
0N/A protected void init(OpenAMParameters parameters) {
0N/A String path = this.openamServer.getPath();
0N/A path = path.endsWith("/") ? path + "UI/Login" : path + "/UI/Login";
0N/A this.openamServer.setPath(path);
0N/A realm = parameters.getOrgName();
0N/A if (OpenAMParameters.IndexType.MODULE.equals(parameters.getLoginIndexType())) {
0N/A moduleName = parameters.getLoginIndexName();
0N/A } else if (OpenAMParameters.IndexType.SERVICE.equals(parameters.getLoginIndexType())) {
0N/A serviceName = parameters.getLoginIndexName();
0N/A }
0N/A }
0N/A
0N/A protected abstract SSOToken getToken(Request request, Response response) throws SSOException;
0N/A
0N/A /**
0N/A * {@inheritDoc}
0N/A */
0N/A @Override
0N/A protected boolean authenticate(Request request, Response response) {
0N/A String prompt = OAuth2Utils.getRequestParameter(request, OAuth2Constants.Custom.PROMPT, String.class);
0N/A String[] prompts = null;
0N/A Set<String> promptSet = null;
0N/A
0N/A //put the space separated prompts into a Set collection
0N/A if (prompt != null && !prompt.isEmpty()){
0N/A prompts = prompt.split(" ");
0N/A }
0N/A if (prompts != null && prompts.length > 0){
0N/A promptSet = new HashSet<String>(Arrays.asList(prompts));
0N/A } else {
0N/A promptSet = new HashSet<String>();
0N/A }
0N/A
0N/A try {
0N/A SSOToken token = getToken(request, response);
0N/A if (promptSet != null && !promptSet.isEmpty() && promptSet.contains("login") && !hasRan){
0N/A hasRan = true;
0N/A return false;
0N/A }
0N/A if (null != token) {
0N/A AMIdentity identity = IdUtils.getIdentity(token);
0N/A
0N/A OpenAMUser user = new OpenAMUser(token.getProperty("UserToken"), token);
0N/A request.getClientInfo().setUser(user);
0N/A return identity.isActive();
0N/A } else {
0N/A if (promptSet != null && !promptSet.isEmpty() && promptSet.contains("none") && promptSet.size() == 1){
0N/A OAuth2Utils.DEBUG.error("Not pre-authenticated and prompt parameter equals none.");
0N/A throw OAuthProblemException.OAuthError.ACCESS_DENIED.handle(request);
0N/A } else if (prompt.contains("none") && promptSet.size() > 1){
0N/A // prompt has more than one value with none error
0N/A OAuth2Utils.DEBUG.error("Prompt parameter only allows none when none is present.");
0N/A throw OAuthProblemException.OAuthError.INVALID_REQUEST.handle(request);
0N/A }
0N/A hasRan = false;
0N/A return false;
0N/A }
0N/A } catch (SSOException e) {
0N/A OAuth2Utils.DEBUG.error("Error authenticating user against OpenAM: ", e );
0N/A redirect(request, response);
0N/A } catch (IdRepoException e) {
0N/A OAuth2Utils.DEBUG.error("Error authenticating user against OpenAM: ", e );
0N/A throw new ResourceException(Status.SERVER_ERROR_INTERNAL, e.getMessage(), e);
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A protected void redirect(Request request, Response response) {
0N/A if (OAuth2Utils.DEBUG.messageEnabled()){
0N/A OAuth2Utils.DEBUG.message("Redirecting to OpenAM login page");
0N/A }
0N/A HttpServletRequest httpRequest = ServletUtils.getRequest(request);
0N/A String authURL = null;
0N/A URI authURI = null;
0N/A
0N/A authURL = getAuthURL(request);
0N/A
0N/A /**
0N/A * TODO check for forward and do a forward vs a redirection See IDPSSOFederate.redirectAuthentication() for details
0N/A //check for forward or request
0N/A StringBuffer appliRootUrl = getAppliRootUrl(httpRequest);
0N/A boolean forward = false;
0N/A StringBuffer newURL;
0N/A // build newUrl to auth service and test if redirect or forward
0N/A
0N/A if(FSUtils.isSameContainer(httpRequest, authURL)){
0N/A forward = true;
0N/A String relativePath = getRelativePath(authURL, appliRootUrl.
0N/A toString());
0N/A newURL = new StringBuffer(relativePath);
0N/A } else {
0N/A // cannot forward so redirect
0N/A forward = false ;
0N/A newURL = new StringBuffer(authURL);
0N/A }
0N/A */
0N/A
0N/A try {
0N/A authURI = new URI(authURL);
0N/A } catch (URISyntaxException e){
0N/A OAuth2Utils.DEBUG.error("Unable to construct authURI", e);
0N/A throw new ResourceException(Status.SERVER_ERROR_INTERNAL, e.getMessage(), e);
0N/A }
0N/A Reference amserver = new Reference(authURI);
0N/A realm = OAuth2Utils.getRealm(request);
0N/A moduleName = OAuth2Utils.getModuleName(request);
0N/A serviceName = OAuth2Utils.getServiceName(request);
0N/A locale = OAuth2Utils.getLocale(request);
0N/A
0N/A if (null != realm && !realm.isEmpty()) {
0N/A amserver.addQueryParameter(OAuth2Constants.Custom.REALM, realm);
0N/A }
0N/A if (null != locale && !locale.isEmpty()){
0N/A amserver.addQueryParameter(OAuth2Constants.Custom.LOCALE, locale);
0N/A }
0N/A if (null != moduleName && !moduleName.isEmpty()) {
0N/A amserver.addQueryParameter(OAuth2Constants.Custom.MODULE, moduleName);
0N/A } else if (null != serviceName && !serviceName.isEmpty()) {
0N/A amserver.addQueryParameter(OAuth2Constants.Custom.SERVICE, serviceName);
0N/A }
0N/A //TODO investigate more options for the LOGIN servlett
0N/A
0N/A amserver.addQueryParameter(OAuth2Constants.Custom.GOTO, request.getResourceRef().toString());
0N/A
0N/A Redirector redirector =
0N/A new Redirector(getContext(), amserver.toString(), Redirector.MODE_CLIENT_FOUND);
0N/A redirector.handle(request, response);
0N/A }
0N/A
0N/A private String getAuthURL(Request request){
0N/A HttpServletRequest httpRequest = ServletUtils.getRequest(request);
0N/A String uri = httpRequest.getRequestURI();
0N/A String deploymentURI = uri;
0N/A int firstSlashIndex = uri.indexOf("/");
0N/A int secondSlashIndex = uri.indexOf("/", firstSlashIndex + 1);
0N/A if (secondSlashIndex != -1) {
0N/A deploymentURI = uri.substring(0, secondSlashIndex);
0N/A }
0N/A StringBuffer sb = new StringBuffer(100);
0N/A sb.append(httpRequest.getScheme()).append("://")
0N/A .append(httpRequest.getServerName()).append(":")
0N/A .append(httpRequest.getServerPort())
0N/A .append(deploymentURI)
0N/A .append("/UI/Login");
0N/A return sb.toString();
0N/A }
0N/A
0N/A /* TODO will be used when forward is implemented
0N/A private static StringBuffer getAppliRootUrl(HttpServletRequest request) {
0N/A StringBuffer result = new StringBuffer();
0N/A String scheme = request.getScheme(); // http
0N/A String serverName = request.getServerName(); // hostname.com
0N/A int serverPort = request.getServerPort(); // 80
0N/A String contextPath = request.getContextPath(); // /mywebapp
0N/A result.append(scheme).append("://").append(serverName).append(":").
0N/A append(serverPort);
0N/A result.append(contextPath);
0N/A return result ;
0N/A }
0N/A
0N/A private static String getRelativePath(String absUrl, String appliRootUrl) {
0N/A return absUrl.substring(appliRootUrl.length(), absUrl.length());
0N/A }
0N/A */
0N/A}
0N/A