com.alliander.osgp.shared.security.CustomAuthenticationManager.java Source code

Java tutorial

Introduction

Here is the source code for com.alliander.osgp.shared.security.CustomAuthenticationManager.java

Source

/**
 * Copyright 2015 Smart Society Services B.V.
 *
 * 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
 */
package com.alliander.osgp.shared.security;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import com.alliander.osgp.shared.usermanagement.AuthenticationClient;
import com.alliander.osgp.shared.usermanagement.AuthenticationClientException;
import com.alliander.osgp.shared.usermanagement.AuthenticationResponse;
import com.alliander.osgp.shared.usermanagement.LoginRequest;
import com.alliander.osgp.shared.usermanagement.LoginResponse;

/**
 * Authentication manager class that offers login and authentication token
 * validation for web applications.
 *
 * The web application must create an instance of CustomAuthenticationManager
 * using an AuthenticationClient instance and a member of enumeration
 * com.alliander.osp.usermanagementweb.domain.Application as application String.
 * The web application shall use the authenticate(Authentication) function to
 * login. Upon successful authentication an CustomAuthentication instance will
 * be returned. The web application shall use the CustomAuthentication instance
 * as argument for the function validateToken(CustomAuthentication) to validate
 * the authentication token. After each validation, a new authentication token
 * is set in the CustomAuthentication instance.
 */
public final class CustomAuthenticationManager implements AuthenticationManager {

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomAuthenticationManager.class);

    private static final String NULL_AUTHENTICATION = "null authentication";
    private static final String NULL_BLANK_USERNAME_CREDENTIALS = "null/blank username/credential";
    private static final String LOGIN_ATTEMPT_FAILED = "login attempt failed";
    private static final String LOGIN_RESPONSE_IS_NULL = "login response is null";
    private static final String LOGIN_RESPONSE_IS_NOT_OK = "login response is not OK";
    private static final String AUTHENTICATION_RESPONSE_IS_NULL = "authentication response is null";
    private static final String AUTHENTICATION_RESPONSE_IS_NOT_OK = "authentication response is not OK";

    private static final String OK = "OK";

    private final AuthenticationClient authenticationClient;
    private final String application;

    /**
     * Construct an instance using
     * com.alliander.osgp.shared.usermanagement.AuthenticationClient and
     * com.alliander.osgp.usermanagementweb.domain.Application as application
     * String
     *
     * @param authenticationClient
     *            The AuthenticationClient instance.
     * @param application
     *            The Application as String.
     */
    public CustomAuthenticationManager(final AuthenticationClient authenticationClient, final String application) {
        this.authenticationClient = authenticationClient;
        this.application = application;
    }

    /**
     * The login function. Use an Authentication instance with the principal set
     * to the user name and the credentials set to the password. Authentication
     * will be granted if the user is permitted for an/this application, the
     * user name is registered and the password matches.
     *
     * @param authentication
     *            An Authentication instance containing user name and password.
     *
     * @return An CustomAuthentication instance containing user name, users
     *         organisation identification, platform domains, user role, user
     *         applications and an authentication token.
     */
    @Override
    public Authentication authenticate(final Authentication authentication) {

        // Check if user has authentication instance.
        this.checkAuthenticationInstance(authentication);

        // Get user name and password.
        final String username = authentication.getName();
        final String password = (String) authentication.getCredentials();

        // Check user name and password.
        this.checkUsernameAndPasswordForEmptiness(username, password);

        // Prepare LoginRequest and LoginResponse.
        final LoginRequest loginRequest = new LoginRequest(username, password, this.application);
        LoginResponse loginResponse = null;

        // Try to login.
        try {

            loginResponse = this.authenticationClient.login(loginRequest);
        } catch (final Exception e) {
            LOGGER.debug(LOGIN_ATTEMPT_FAILED, e);
            throw new BadCredentialsException(LOGIN_ATTEMPT_FAILED, e);
        }

        // Check the response.
        this.checkLoginResponse(loginResponse);

        // Create the CustomAuthentication instance.
        return this.createCustomAuthenticationInstance(username, password, loginResponse);
    }

    private void checkAuthenticationInstance(final Authentication authentication) {

        // Check if user has authentication instance.
        if (authentication == null) {
            LOGGER.debug(NULL_AUTHENTICATION);
            throw new BadCredentialsException(NULL_AUTHENTICATION);
        }
    }

    private void checkUsernameAndPasswordForEmptiness(final String username, final String password) {

        // Check user name and password.
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            LOGGER.debug(NULL_BLANK_USERNAME_CREDENTIALS);
            throw new BadCredentialsException(NULL_BLANK_USERNAME_CREDENTIALS);
        }
    }

    private void checkLoginResponse(final LoginResponse loginResponse) {

        // Check if the response equals null.
        if (loginResponse == null) {
            LOGGER.debug(LOGIN_RESPONSE_IS_NULL);
            throw new BadCredentialsException(LOGIN_RESPONSE_IS_NULL);
        }

        // Check if the response is OK.
        if (!loginResponse.getFeedbackMessage().equals(OK)) {
            LOGGER.debug(LOGIN_RESPONSE_IS_NOT_OK);
            throw new BadCredentialsException(LOGIN_RESPONSE_IS_NOT_OK);
        }
    }

    private CustomAuthentication createCustomAuthenticationInstance(final String username, final String password,
            final LoginResponse loginResponse) {

        // Create the instance.
        final CustomAuthentication customAuthentication = new CustomAuthentication();
        customAuthentication.setAuthenticated(true);
        customAuthentication.setUserName(username);
        customAuthentication.setCredentials(password);
        customAuthentication.setOrganisationIdentification(loginResponse.getOrganisationIdentification());
        customAuthentication.setDomains(loginResponse.getDomains());
        customAuthentication.getAuthorities().clear();
        final GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(loginResponse.getRole());
        customAuthentication.getAuthorities().add(grantedAuthority);
        customAuthentication.setApplications(loginResponse.getApplications());
        customAuthentication.setToken(loginResponse.getToken());

        return customAuthentication;
    }

    /**
     * Check the validity of an authentication token.
     *
     * @param authentication
     *            The CustomAuthentication instance obtained by successful
     *            authentication.
     *
     * @throws AuthenticationClientException
     *             In case the organisationIdentification or token are an empty
     *             string, the token is not valid, the response is null, the
     *             HTTP status code is not equal to 200 OK or if the response
     *             body is empty.
     */
    public void validateToken(final CustomAuthentication authentication) throws AuthenticationClientException {

        // Check if user has authentication instance.
        this.checkAuthenticationInstance(authentication);

        // Set authenticated to false.
        // authentication.setAuthenticated(false);

        final String organisationIdentification = authentication.getOrganisationIdentification();
        final String token = authentication.getToken();

        final AuthenticationResponse authenticationResponse = this.authenticationClient
                .authenticate(organisationIdentification, token);

        // Check the response.
        this.checkAuthenticationResponse(authenticationResponse, authentication);

        // Set authenticated to true, set the new token and user name.
        authentication.setToken(authenticationResponse.getToken());
        authentication.setUserName(authenticationResponse.getUserName());
        authentication.setAuthenticated(true);
    }

    private void checkAuthenticationResponse(final AuthenticationResponse authenticationResponse,
            final CustomAuthentication authentication) throws AuthenticationClientException {

        // Check if the response equals null.
        if (authenticationResponse == null) {
            LOGGER.debug(AUTHENTICATION_RESPONSE_IS_NULL);
            // Set authenticated to false.
            authentication.setAuthenticated(false);
            throw new AuthenticationClientException(AUTHENTICATION_RESPONSE_IS_NULL);
        }

        // Check if the response is OK.
        if (!authenticationResponse.getFeedbackMessage().equals(OK)) {
            LOGGER.debug(AUTHENTICATION_RESPONSE_IS_NOT_OK);
            // Set authenticated to false.
            authentication.setAuthenticated(false);
            throw new AuthenticationClientException(AUTHENTICATION_RESPONSE_IS_NOT_OK);
        }
    }
}