it.geosolutions.figis.security.authentication.CredentialsManager.java Source code

Java tutorial

Introduction

Here is the source code for it.geosolutions.figis.security.authentication.CredentialsManager.java

Source

/*
 * ====================================================================
 *
 * Intersection Engine
 *
 * Copyright (C) 2007 - 2011 GeoSolutions S.A.S.
 * http://www.geo-solutions.it
 *
 * GPLv3 + Classpath exception
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.
 *
 * ====================================================================
 *
 * This software consists of voluntary contributions made by developers
 * of GeoSolutions.  For more information on GeoSolutions, please see
 * <http://www.geo-solutions.it/>.
 *
 */
package it.geosolutions.figis.security.authentication;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import it.geosolutions.figis.model.User;
import it.geosolutions.figis.model.enums.Role;

import org.apache.commons.io.IOUtils;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.springframework.security.access.AccessDeniedException;

public class CredentialsManager {

    /** Default period for the credentials reloader**/
    public static final int DEFAULT_RELOAD_PERIOD = 60 * 1000;

    static final Logger LOGGER = Logger.getLogger(CredentialsManager.class.toString());

    /** The SEPARATOR: possible to config it by applicationContext.xml  */
    private static String SEPARATOR = "@";

    private String PROPERTIES_FILE;

    private long period = DEFAULT_RELOAD_PERIOD;

    private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

    private final Lock r = rwl.readLock();

    private final Lock w = rwl.writeLock();

    private String usersRoleAdmin;

    private String usersRoleUser;

    private long lastMod = 0;

    private File propertyFile;

    public CredentialsManager(String propertiesFile, String usersRoleAdmin, String usersRoleUser, long period)
            throws IOException {
        if (propertiesFile == null) {
            throw new IllegalArgumentException("userca.properties: PROPERTIES_FILE key is null");
        }
        if (usersRoleAdmin == null) {
            throw new IllegalArgumentException("userca.properties: usersRoleAdmin key is null");
        }
        if (usersRoleUser == null) {
            throw new IllegalArgumentException("userca.properties: usersRoleUser key is null");
        }
        if (period <= 0) {
            throw new IllegalArgumentException("Wrong period provided:" + period);
        }

        PROPERTIES_FILE = propertiesFile;

        java.net.URL url = this.getClass().getClassLoader().getResource(propertiesFile);
        try {
            propertyFile = new File(url.toURI());
            if (!propertyFile.isFile() || !propertyFile.canRead() || propertyFile.isHidden()) {
                throw new IllegalArgumentException("Unable to reach file:" + url.toURI().toString() + "\n"
                        + "canRead:" + propertyFile.canRead() + ",isFile:" + propertyFile.isFile() + ",isHidden:"
                        + propertyFile.isHidden());
            }
            lastMod = propertyFile.lastModified();
        } catch (Exception se) {
            LOGGER.error(se.getLocalizedMessage(), se);
            throw new RuntimeException(
                    "UsersCheckUtils: error on reading file properties: PROPERTIES_FILE: " + propertiesFile);
        }

        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("Checked PROPERTIES_FILE: " + propertiesFile);
        }
        loadProperties();
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("Assigned new properties from file: PROPERTIES_FILE: " + propertiesFile);
        }

        // set the period and start the reloader
        this.period = period;
        new CredentialsManager.Reloader().start();
    }

    /**
     *
     */
    public synchronized void reload() {
        // get new modified time
        final long tempModTime = propertyFile.lastModified();

        // do we need to reload the properties file
        if (tempModTime > lastMod) {
            try {

                // reload
                loadProperties();

                // update the modified time only when we actually succeed in reloading
                lastMod = tempModTime;
            } catch (IOException e) {
                if (LOGGER.isEnabledFor(Level.INFO)) {
                    LOGGER.log(Level.INFO, e.getLocalizedMessage(), e);
                }
            }
        }
    }

    /**
     *
     * @throws IOException
     */
    private void loadProperties() throws IOException {
        Properties props = new Properties();
        InputStream pin = null;
        try {
            pin = new BufferedInputStream(new FileInputStream(propertyFile));

            if (LOGGER.isTraceEnabled()) {
                LOGGER.trace("PROPERTIES_FILE reloaded " + PROPERTIES_FILE);
            }

            props.load(pin);

            if (LOGGER.isTraceEnabled()) {
                LOGGER.trace("PROPERTIES_FILE reloaded: " + PROPERTIES_FILE);
            }
        } catch (IOException e) {
            throw new IOException(
                    "UsersCheckUtils: error on realoading file properties: PROPERTIES_FILE: " + PROPERTIES_FILE);
        } finally {
            if (pin != null) {
                IOUtils.closeQuietly(pin);
            }
        }

        String temp = null;
        w.lock();
        try {
            if (props.containsKey("PROPERTIES_FILE")) {
                temp = props.getProperty("PROPERTIES_FILE");
                if (temp != null) {
                    PROPERTIES_FILE = temp;
                }
            }

            if (props.containsKey("usersRoleAdmin")) {
                temp = props.getProperty("usersRoleAdmin");
                if (temp != null) {
                    usersRoleAdmin = props.getProperty("usersRoleAdmin");
                }
            }

            if (props.containsKey("usersRoleUser")) {
                temp = props.getProperty("usersRoleUser");
                if (temp != null) {
                    usersRoleUser = props.getProperty("usersRoleUser");
                }
            }

        } finally {
            w.unlock();
        }

    }

    /**
    * This method return the User authenticated or throw new AccessDeniedException
    *
    * @param usernameIn: username to match
    * @param passwordIn: password to match
    * @return The User
    * @throws AccessDeniedException
    */
    public User getUser(String usernameIn, String passwordIn) throws AccessDeniedException {

        r.lock();
        try {
            if ((usersRoleAdmin == null) && (usersRoleUser == null)) {
                throw new AccessDeniedException("User not mapping");
            }

            String userToCheck = usernameIn + SEPARATOR + passwordIn;
            final User user = new User();
            // check users authorization

            if ((usersRoleAdmin != null) && usersRoleAdmin.contentEquals(userToCheck)) {
                user.setName(usernameIn);
                user.setPassword(passwordIn);
                user.setRole(Role.valueOf("ADMIN"));

                return user;
            }
            if ((usersRoleAdmin != null) && usersRoleUser.contentEquals(userToCheck)) {
                user.setName(usernameIn);
                user.setPassword(passwordIn);
                user.setRole(Role.valueOf("USER"));

                return user;
            }
            throw new AccessDeniedException("Not authorized");
        } finally {
            r.unlock();
        }
    }

    /**
     * Periodic reloader for the configuration.
     * @author Simone Giannecchini, GeoSolutions SAs
     *
     */
    private final class Reloader extends Thread {

        public Reloader() {
            this.setDaemon(true);
            this.setName("USERS_CREDENTIALS_RELOADER");
            this.setPriority(NORM_PRIORITY - 1);
        }

        @Override
        public void run() {
            super.run();
            while (true) {
                CredentialsManager.this.reload();

                synchronized (this) {
                    try {
                        this.wait(CredentialsManager.this.period);
                    } catch (InterruptedException e) {
                        CredentialsManager.LOGGER.error("RELOADING DAEMON STOPPED!!!", e);
                    }
                }
            }
        }

    }

}