edu.uniandes.ecos.codeaholics.config.Authorization.java Source code

Java tutorial

Introduction

Here is the source code for edu.uniandes.ecos.codeaholics.config.Authorization.java

Source

/** Copyright or License
 *
 */

package edu.uniandes.ecos.codeaholics.config;

import static spark.Spark.halt;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bson.Document;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import spark.Request;
import spark.Response;

import edu.uniandes.ecos.codeaholics.exceptions.AuthorizationException.*;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;

/**
 * 
 */
/**
 * Package: edu.uniandes.ecos.codeaholics.config
 *
 * Class: Authorization Authorization.java
 * 
 * Original Author: @author davidMtz and @author AOSORIO
 * 
 * Description: Autorization works as a Stateless Session Manager (does not keep
 * track of the state of sessions.
 * 
 * Implementation: Autorization method JWT
 *
 * Created: Oct 28, 2016 9:15:25 AM
 * 
 */
public final class Authorization {

    // Atributos
    private final static Logger log = LogManager.getLogger(Authorization.class);

    private static String authenticationMethod = "JWT"; // ... JWT, Simple

    // Metodos

    /**
     * Generic procedure to autorize any User with a provided Profile (citizen,
     * functionary, admin)
     * 
     * @param pRequest
     * @param pResponse
     * @param pUserProfile
     * @return Message (String) depending on the authorization result
     */
    public static String authorizeUser(Request pRequest, Response pResponse, String pUserProfile) {

        if (pRequest.headers("Authorization") == null) {
            return "No Authorization in header. Ignore.";
        }

        boolean isAutorized = false;
        String token = pRequest.headers("Authorization").split(" ")[1];

        log.info("Token: " + token);

        if (!token.isEmpty()) {

            try {

                Document session = new Document();
                session.append("token", token);
                session.append("user-profile", pUserProfile);

                isAutorized = findSession(session);

            } catch (ExpiredTokenException authEx) {

                log.info(authEx.getMessage());
                isAutorized = false;

            } catch (FunctionalityAuthorizationException authEx) {

                log.info(authEx.getMessage());
                isAutorized = false;
            } catch (Exception ex) {

                log.info("Something went wrong!");
                ex.getMessage();
            }

            if (!isAutorized) {
                halt(401, "No eres bienvenido aqui");
                return "No hay autorizacion";
            }

        }

        log.info("Termina proceso de autorizacion con exito");

        return "Proceso de autorizacion realizado";

    }

    /**
     * Valida si lo datos corresponden a ciudadano con una sesion creada en el
     * sistema.
     *
     * @param pRequest
     *            request
     * @param pResponse
     *            response
     * @return resultado de la verificacion
     */
    public static String authorizeCitizen(Request pRequest, Response pResponse) {

        return authorizeUser(pRequest, pResponse, Constants.CITIZEN_USER_PROFILE);

    }

    /**
     * Valida si lo datos corresponden a funcionario con una sesion creada en el
     * sistema.
     *
     * @param pRequest
     *            request
     * @param pResponse
     *            response
     * @return resultado de la verificacin
     */
    public static String authorizeFuntionary(Request pRequest, Response pResponse) {

        return authorizeUser(pRequest, pResponse, Constants.FUNCTIONARY_USER_PROFILE);

    }

    /**
     * Valida si lo datos corresponden a administrador de alcaldia con una
     * sesion creada en el sistema.
     *
     * @param pRequest
     *            request
     * @param pResponse
     *            response
     * @return resultado de la verificacin
     */
    public static String authorizeAdmin(Request pRequest, Response pResponse) {

        return authorizeUser(pRequest, pResponse, Constants.ADMIN_USER_PROFILE);

    }

    /**
     * looks for a a session in DB. Checks arriving token validity
     * 
     * @param pSession
     * @return
     * @throws FunctionalityAuthorizationException
     * @throws ExpiredTokenException
     */
    public static boolean findSession(Document pSession)
            throws FunctionalityAuthorizationException, ExpiredTokenException {

        boolean isAuthorized = false;

        ArrayList<Document> documents = DataBaseUtil.find(pSession, Constants.SESSION_COLLECTION);

        if (documents.size() > 0) {

            log.info("User has a open session");

            if (authenticationMethod.equals("JWT")) {

                try {

                    Document session = documents.get(0);
                    String storedSalt = session.getString("salt");

                    checkTokenValidity(pSession.getString("token"), storedSalt);
                    isAuthorized = true;

                } catch (ExpiredTokenException ex) {
                    log.info(ex.getMessage());
                    throw ex;
                } catch (Exception ex) {
                    log.info("Something went wrong!");
                    ex.getMessage();
                }

                log.info("Usuario tiene sesion valida");

            }

        } else {
            log.info("Usuario no tiene sesion");
            isAuthorized = false;
            throw new FunctionalityAuthorizationException("No se encuentra sesion del usuario", "402");
        }

        return isAuthorized;

    }

    /**
     * Checks the validity of the token - if token has expired throws expection
     * 
     * @param pToken
     * @param pSalt
     * @throws ExpiredTokenException
     *             : custom exception (wraps the jwt library exception).
     */
    private static void checkTokenValidity(String pToken, String pSalt) throws ExpiredTokenException {

        // 1. Extract expiration date
        try {

            String email = (String) getTokenClaim(pToken, pSalt, Constants.TOKEN_EMAIL_KEY);

            log.info("token has email: " + email);

            Claims claims = Jwts.parser().setSigningKey(pSalt).parseClaimsJws(pToken).getBody();

            log.info("Token is currently valid");

            Date expDate = claims.getExpiration();
            log.info("Expiration: " + expDate);

            long nowMillis = System.currentTimeMillis();
            Date now = new Date(nowMillis);

            long diff = now.getTime() - expDate.getTime();

            if (diff < (60000)) { // this token will expired soon

            }

        } catch (ExpiredJwtException jwtEx) {
            log.info(jwtEx.getLocalizedMessage());
            throw new ExpiredTokenException("Token ha expirado", "505");
        }

    }

    /**
     * Get from token the correspoding Claim with key pKey - this method uses
     * the signature (+secret)
     * 
     * @param pToken
     * @param pSalt
     *            : the secret used to verify the token
     * @param pKey
     * @return
     * @throws ExpiredJwtException
     *             : in case the token has expired
     */
    public static Object getTokenClaim(String pToken, String pSalt, String pKey) throws ExpiredJwtException {

        Object obj = null;
        try {
            obj = Jwts.parser().setSigningKey(pSalt).parseClaimsJws(pToken).getBody().get(pKey);
        } catch (ExpiredJwtException jwtEx) {
            throw jwtEx;
        }
        return obj;

    }

    /**
     * Get from token body the corresponding Claim with key pKey
     * 
     * @param pJwt
     * @param pKey
     * @return
     * @throws InvalidTokenException
     *             : in case the token has not three parts or if claim is not
     *             found
     */
    public static String getTokenClaim(String pJwt, String pKey) throws InvalidTokenException {

        String[] jwtElements = pJwt.split("\\.");

        if (jwtElements.length < 3) {
            throw new InvalidTokenException("Token is invalid", "505");
        }

        String value = null;

        ByteArrayInputStream inStream = new ByteArrayInputStream(Base64.getDecoder().decode(jwtElements[1]));

        BufferedReader streamReader = new BufferedReader(new InputStreamReader(inStream));
        StringBuilder responseStrBuilder = new StringBuilder();
        String inputStr;

        try {
            while ((inputStr = streamReader.readLine()) != null)
                responseStrBuilder.append(inputStr);

            JsonParser parser = new JsonParser();
            JsonObject json = parser.parse(responseStrBuilder.toString()).getAsJsonObject();

            if (json.getAsJsonObject().has(pKey)) {
                value = json.getAsJsonObject().get(pKey).getAsString();
                log.info("Found key with value: " + value);
            } else {
                throw new InvalidTokenException("Token is invalid", "505");
            }

        } catch (IOException e) {
            e.printStackTrace();

        }

        return value;
    }

    /** Get from the Request, the token and then from it extract the needed Claim
     * @param pRequest
     * @param pClaim
     * @return
     * @throws InvalidTokenException
     */
    public static String getFromToken(Request pRequest, String pClaim) throws InvalidTokenException {

        String token = pRequest.headers("Authorization").split(" ")[1];
        try {
            return Authorization.getTokenClaim(token, pClaim);
        } catch (InvalidTokenException ex) {
            throw ex;
        }

    }

}