com.ibm.sbt.services.endpoints.BasicEndpoint.java Source code

Java tutorial

Introduction

Here is the source code for com.ibm.sbt.services.endpoints.BasicEndpoint.java

Source

/*
 *  Copyright IBM Corp. 2012
 * 
 * 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 com.ibm.sbt.services.endpoints;

import java.io.IOException;
import java.net.URLEncoder;

import javax.servlet.http.HttpServletRequest;

import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.impl.auth.BasicSchemeFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.protocol.HttpContext;

import com.ibm.commons.runtime.Context;
import com.ibm.commons.runtime.util.UrlUtil;
import com.ibm.commons.util.PathUtil;
import com.ibm.commons.util.StringUtil;
import com.ibm.sbt.security.authentication.AuthenticationException;
import com.ibm.sbt.security.authentication.password.consumer.UserPassword;
import com.ibm.sbt.security.credential.store.CredentialStore;
import com.ibm.sbt.security.credential.store.CredentialStoreException;
import com.ibm.sbt.security.credential.store.CredentialStoreFactory;
import com.ibm.sbt.service.core.handlers.AuthCredsHandler;
import com.ibm.sbt.service.core.servlet.ServiceServlet;
import com.ibm.sbt.services.client.ClientServicesException;
import com.ibm.sbt.services.endpoints.js.JSReference;

/**
 * Bean that provides a basic authentication.
 * <p>
 * </p>
 * @author Philippe Riand
 */
public class BasicEndpoint extends AbstractEndpoint {

    // Key used by the bean when it needs to redirect
    public static final String REDIRECT_PAGE_KEY = "xsp.endpoint.redirectpage";

    // Type used to store the credentials
    public static final String STORE_TYPE = "Basic";

    private String user;
    private String password;
    private String authenticationPage;
    private boolean storeAlreadyTried;

    public BasicEndpoint() {
    }

    public BasicEndpoint(String user, String password, String authenticationPage) {
        this.user = user;
        this.password = password;
        this.authenticationPage = authenticationPage;
    }

    @Override
    public JSReference getAuthenticator(String endpointName, String sbtUrl) {
        JSReference reference = new JSReference("sbt/authenticator/Basic");
        reference.getProperties().put("url", sbtUrl);

        return reference;
    }

    @Override
    public String getUserIdentity() throws ClientServicesException {
        try {
            String u = getUser();
            if (StringUtil.isEmpty(u)) {
                readFromStore();
                u = getUser();
            }
            return u;
        } catch (AuthenticationException ex) {
            throw new ClientServicesException(ex);
        }
    }

    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getAuthenticationPage() {
        if (StringUtil.isEmpty(authenticationPage)) {
            // return default authentication page if it is not given in managed bean
            return "/sbt/loginForm.html";
        }
        return authenticationPage;
    }

    public void setAuthenticationPage(String authenticationPage) {
        this.authenticationPage = authenticationPage;
    }

    @Override
    public String getAuthType() {
        return "basic";
    }

    @Override
    public boolean isAuthenticated() throws ClientServicesException {
        try {
            String u = getUser();
            if (StringUtil.isEmpty(u)) {
                return readFromStore();
            }
            return true;
        } catch (AuthenticationException ex) {
            throw new ClientServicesException(ex);
        }
    }

    @Override
    public void authenticate(boolean force) throws ClientServicesException {
        if ((HttpServletRequest) Context.get().getHttpRequest() == null) {
            return;
        }
        if (force || !isAuthenticated()) {
            String authPage = getAuthenticationPage();
            Context context = Context.get();
            if (StringUtil.isNotEmpty(authPage)) {
                // to ignore if the authentication page value contains endpoint parameter, we are now making use of this.getName() to get the endpoint name
                // and no need to explicitly set in authentication page value
                if (authPage.contains("?endpoint=") || authPage.contains("?")) {
                    authPage = authPage.substring(0, authPage.indexOf(("?")));
                }
                try {
                    if (!UrlUtil.isAbsoluteUrl(authPage)) {
                        authPage = UrlUtil.makeUrlAbsolute((HttpServletRequest) context.getHttpRequest(), authPage);
                    }

                    String redirectUrl = UrlUtil.getRequestUrl((HttpServletRequest) context.getHttpRequest());// change needed to handle portlethttprequest

                    String endPointName = this.getName();
                    String baseUrl = UrlUtil.getBaseUrl(((HttpServletRequest) context.getHttpRequest()));
                    String servletPath = ServiceServlet.getServletPath();
                    String basicProxyUrl = AuthCredsHandler.URL_PATH;

                    //constructing proxy action url
                    String postToProxy = PathUtil.concat(baseUrl, servletPath, '/');
                    postToProxy = PathUtil.concat(postToProxy, basicProxyUrl, '/');
                    postToProxy = PathUtil.concat(postToProxy, endPointName, '/');
                    postToProxy = PathUtil.concat(postToProxy, "JavaApp", '/');

                    // encode URL's
                    postToProxy = URLEncoder.encode(postToProxy, "UTF-8");
                    redirectUrl = URLEncoder.encode(redirectUrl, "UTF-8");

                    // passing proxy action url as a parameter to the authentication page
                    authPage = PathUtil.concat(authPage, "proxyPath", '?');
                    authPage = PathUtil.concat(authPage, postToProxy, '=');
                    // passing redirectURL as a parameter to the authentication page
                    authPage = PathUtil.concat(authPage, "redirectURL", '&');
                    authPage = PathUtil.concat(authPage, redirectUrl, '=');
                    context.sendRedirect(authPage);

                } catch (IOException e) {
                    throw new ClientServicesException(null,
                            "Authentication page not found. Could not redirect to login page");
                }
            } else {
                throw new ClientServicesException(null,
                        "Authentication page is empty in the basic authentication bean");
            }
        }
    }

    public boolean readFromStore() throws AuthenticationException {
        try {
            if (!storeAlreadyTried) {
                synchronized (this) {
                    Context context = Context.getUnchecked();
                    if (context != null) {
                        UserPassword u = null;
                        CredentialStore cs = CredentialStoreFactory.getCredentialStore(getCredentialStore());
                        if (cs != null) {
                            u = (UserPassword) cs.load(getUrl(), STORE_TYPE, context.getCurrentUserId());
                        }
                        if (u != null) {
                            this.user = u.getUser();
                            this.password = u.getPassword();
                            return true;
                        }
                        storeAlreadyTried = true;
                    }
                }
            }
            return false;
        } catch (CredentialStoreException ex) {
            throw new AuthenticationException(ex, "Error while reading basic credentials from the store");
        }
    }

    public boolean writeToStore() throws AuthenticationException {
        try {
            Context context = Context.getUnchecked();
            if (context != null) {
                CredentialStore cs = CredentialStoreFactory.getCredentialStore(getCredentialStore());
                if (cs != null) {
                    UserPassword u = new UserPassword(user, password);
                    cs.store(getUrl(), STORE_TYPE, context.getCurrentUserId(), u);
                    return true;
                }
            }
            return false;
        } catch (CredentialStoreException ex) {
            throw new AuthenticationException(ex, "Error while writing basic credentials to the store");
        }
    }

    public boolean clearFromStore() throws AuthenticationException {
        try {
            Context context = Context.getUnchecked();
            if (context != null) {
                CredentialStore cs = CredentialStoreFactory.getCredentialStore(getCredentialStore());
                if (cs != null) {
                    cs.remove(getUrl(), STORE_TYPE, context.getCurrentUserId());
                    return true;
                }
            }
            return false;
        } catch (CredentialStoreException ex) {
            throw new AuthenticationException(ex, "Error while deleting basic credentials from the store");
        }
    }

    public boolean login(String user, String password) throws AuthenticationException {
        return login(user, password, false);
    }

    public boolean login(String user, String password, boolean writeToStore) throws AuthenticationException {
        setUser(user);
        setPassword(password);
        if (!isAuthenticationValid()) {
            setUser(null);
            setPassword(null);
            return false;
        }
        if (writeToStore) {
            writeToStore();
        } else {
            clearFromStore();
        }
        // How can we verify the user is properly authenticated?
        return true;
    }

    @Override
    public void logout() throws AuthenticationException {
        setUser(null);
        setPassword(null);
        clearFromStore();
    }

    public void redirect() throws ClientServicesException {
        Context context = Context.get();

        String nextPage = (String) context.getSessionMap().get(REDIRECT_PAGE_KEY);
        if (StringUtil.isEmpty(nextPage))
            nextPage = ((HttpServletRequest) context.getHttpRequest()).getParameter("redirectURL");
        if (StringUtil.isNotEmpty(nextPage)) {
            // TODO
            // context.getExternalContext().getSessionMap().remove(REDIRECT_PAGE_KEY);
            // XSPContext ctx =
            // XSPContext.getXSPContext(FacesContext.getCurrentInstance());
            try {
                context.sendRedirect(nextPage);
            } catch (IOException e) {
                throw new ClientServicesException(e, "Error redirecting to the following URL" + nextPage);
            }
        }
    }

    @Override
    public void initialize(DefaultHttpClient httpClient) throws ClientServicesException {
        String usr = getUserIdentity();
        if (StringUtil.isNotEmpty(usr)) {
            String pwd = getPassword();

            UsernamePasswordCredentials creds = new UsernamePasswordCredentials(usr, pwd);

            HttpRequestInterceptor basicInterceptor = new BasicInterceptor(creds);
            httpClient.addRequestInterceptor(basicInterceptor, 0);
        }
    }

    private static class BasicInterceptor implements HttpRequestInterceptor {

        private UsernamePasswordCredentials credentials;

        public BasicInterceptor(UsernamePasswordCredentials credentials) {
            this.credentials = credentials;
        }

        @Override
        public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
            AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
            if (authState != null && authState.getAuthScheme() == null) {
                AuthScheme scheme = new BasicSchemeFactory().newInstance(new BasicHttpParams());
                authState.setAuthScheme(scheme);
                authState.setCredentials(credentials);
            }
        }
    }
}