org.nuxeo.ecm.tokenauth.servlet.TokenAuthenticationServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.nuxeo.ecm.tokenauth.servlet.TokenAuthenticationServlet.java

Source

/*
 * (C) Copyright 2006-2012 Nuxeo SA (http://nuxeo.com/) and others.
 *
 * 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.
 *
 * Contributors:
 *     Antoine Taillefer
 */
package org.nuxeo.ecm.tokenauth.servlet;

import java.io.IOException;
import java.io.OutputStream;
import java.security.Principal;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.util.URIUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuxeo.ecm.core.api.NuxeoPrincipal;
import org.nuxeo.ecm.platform.ui.web.auth.service.AuthenticationPluginDescriptor;
import org.nuxeo.ecm.platform.ui.web.auth.service.PluggableAuthenticationService;
import org.nuxeo.ecm.platform.ui.web.auth.token.TokenAuthenticator;
import org.nuxeo.ecm.tokenauth.TokenAuthenticationException;
import org.nuxeo.ecm.tokenauth.service.TokenAuthenticationService;
import org.nuxeo.runtime.api.Framework;

/**
 * Servlet that allows to get a unique authentication token given the request Principal and some device information
 * passed as request parameters: application name, device id, device description, permission. An error response will be
 * sent with a 400 status code if one of the required parameters is null or empty. All parameters are required except
 * for the device description.
 * <p>
 * The token is provided by the {@link TokenAuthenticationService}.
 *
 * @author Antoine Taillefer (ataillefer@nuxeo.com)
 * @since 5.7
 */
public class TokenAuthenticationServlet extends HttpServlet {

    private static final long serialVersionUID = 7792388601558509103L;

    private static final Log log = LogFactory.getLog(TokenAuthenticationServlet.class);

    protected static final String TOKEN_AUTH_PLUGIN_NAME = "TOKEN_AUTH";

    protected static final String APPLICATION_NAME_PARAM = "applicationName";

    protected static final String DEVICE_ID_PARAM = "deviceId";

    protected static final String DEVICE_DESCRIPTION_PARAM = "deviceDescription";

    protected static final String PERMISSION_PARAM = "permission";

    protected static final String REVOKE_PARAM = "revoke";

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // Don't provide token for anonymous user unless 'allowAnonymous' parameter is explicitly set to true in
        // the authentication plugin configuration
        Principal principal = req.getUserPrincipal();
        if (principal instanceof NuxeoPrincipal && ((NuxeoPrincipal) principal).isAnonymous()) {
            PluggableAuthenticationService authenticationService = (PluggableAuthenticationService) Framework
                    .getRuntime().getComponent(PluggableAuthenticationService.NAME);
            AuthenticationPluginDescriptor tokenAuthPluginDesc = authenticationService
                    .getDescriptor(TOKEN_AUTH_PLUGIN_NAME);
            if (tokenAuthPluginDesc == null || !(Boolean
                    .valueOf(tokenAuthPluginDesc.getParameters().get(TokenAuthenticator.ALLOW_ANONYMOUS_KEY)))) {
                log.debug("Anonymous user is not allowed to acquire an authentication token.");
                resp.sendError(HttpStatus.SC_UNAUTHORIZED);
                return;
            }

        }

        // Get request parameters
        String applicationName = req.getParameter(APPLICATION_NAME_PARAM);
        String deviceId = req.getParameter(DEVICE_ID_PARAM);
        String deviceDescription = req.getParameter(DEVICE_DESCRIPTION_PARAM);
        String permission = req.getParameter(PERMISSION_PARAM);
        String revokeParam = req.getParameter(REVOKE_PARAM);
        boolean revoke = Boolean.valueOf(revokeParam);

        // If one of the required parameters is null or empty, send an
        // error with the 400 status
        if (!revoke && (StringUtils.isEmpty(applicationName) || StringUtils.isEmpty(deviceId)
                || StringUtils.isEmpty(permission))) {
            log.error(
                    "The following request parameters are mandatory to acquire an authentication token: applicationName, deviceId, permission.");
            resp.sendError(HttpStatus.SC_BAD_REQUEST);
            return;
        }
        if (revoke && (StringUtils.isEmpty(applicationName) || StringUtils.isEmpty(deviceId))) {
            log.error(
                    "The following request parameters are mandatory to revoke an authentication token: applicationName, deviceId.");
            resp.sendError(HttpStatus.SC_BAD_REQUEST);
            return;
        }

        // Decode parameters
        applicationName = URIUtil.decode(applicationName);
        deviceId = URIUtil.decode(deviceId);
        if (!StringUtils.isEmpty(deviceDescription)) {
            deviceDescription = URIUtil.decode(deviceDescription);
        }
        if (!StringUtils.isEmpty(permission)) {
            permission = URIUtil.decode(permission);
        }

        // Get user name from request Principal
        if (principal == null) {
            resp.sendError(HttpStatus.SC_UNAUTHORIZED);
            return;
        }
        String userName = principal.getName();

        // Write response
        String response = null;
        int statusCode;
        TokenAuthenticationService tokenAuthService = Framework.getLocalService(TokenAuthenticationService.class);
        try {
            // Token acquisition: acquire token and write it to the response
            // body
            if (!revoke) {
                response = tokenAuthService.acquireToken(userName, applicationName, deviceId, deviceDescription,
                        permission);
                statusCode = 201;
            }
            // Token revocation
            else {
                String token = tokenAuthService.getToken(userName, applicationName, deviceId);
                if (token == null) {
                    response = String.format(
                            "No token found for userName %s, applicationName %s and deviceId %s; nothing to do.",
                            userName, applicationName, deviceId);
                    statusCode = 400;
                } else {
                    tokenAuthService.revokeToken(token);
                    response = String.format("Token revoked for userName %s, applicationName %s and deviceId %s.",
                            userName, applicationName, deviceId);
                    statusCode = 202;
                }
            }
            sendTextResponse(resp, response, statusCode);
        } catch (TokenAuthenticationException e) {
            // Should never happen as parameters have already been checked
            resp.sendError(HttpStatus.SC_NOT_FOUND);
        }
    }

    protected void sendTextResponse(HttpServletResponse resp, String textResponse, int statusCode)
            throws IOException {

        resp.setContentType("text/plain");
        resp.setStatus(statusCode);
        resp.setContentLength(textResponse.getBytes().length);
        OutputStream out = resp.getOutputStream();
        out.write(textResponse.getBytes());
        out.close();
    }

}