org.nimbustools.messaging.query.security.FileUserDetailsService.java Source code

Java tutorial

Introduction

Here is the source code for org.nimbustools.messaging.query.security.FileUserDetailsService.java

Source

/*
 * Copyright 1999-2009 University of Chicago
 *
 * 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 org.nimbustools.messaging.query.security;

import org.springframework.core.io.Resource;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataRetrievalFailureException;
import org.mortbay.util.QuotedStringTokenizer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.HashMap;
import java.util.NoSuchElementException;

/**
 * Placeholder UserDetailsService which loads users from a file.
 *
 * The file format is one user per line: DN accessID secret
 * Any token may be quoted and they are separated by whitespace.
 * Lines starting with # are ignored
 */
public class FileUserDetailsService implements QueryUserDetailsService {

    private static final Log logger = LogFactory.getLog(FileUserDetailsService.class.getName());
    private static final String DELIMS = " \t\n\r\f";

    final private Object lock = new Object();

    private File file;
    private long lastModified;

    final private Map<String, QueryUser> mapByID;
    final private Map<String, QueryUser> mapByDN;

    public FileUserDetailsService(Resource fileResource) throws IOException {
        if (fileResource == null) {
            throw new IllegalArgumentException("fileResource may not be null");
        }

        mapByID = new HashMap<String, QueryUser>();
        mapByDN = new HashMap<String, QueryUser>();

        load(fileResource.getFile());
    }

    public QueryUser loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {

        if (username == null) {
            throw new IllegalArgumentException("username may not be null");
        }

        synchronized (this.lock) {

            this.refreshIfNeeded();

            final QueryUser user = mapByID.get(username);
            if (user != null) {
                return user;
            }

            throw new UsernameNotFoundException("access identifier '" + username + "' unknown");
        }
    }

    public QueryUser loadUserByDn(String dn) throws UsernameNotFoundException, DataAccessException {
        if (dn == null) {
            throw new IllegalArgumentException("dn may not be null");
        }
        synchronized (this.lock) {

            this.refreshIfNeeded();

            final QueryUser user = mapByDN.get(dn);
            if (user != null) {
                return user;
            }

            throw new UsernameNotFoundException("DN '" + dn + "' unknown");
        }
    }

    public boolean refreshIfNeeded() throws DataAccessException {
        synchronized (this.lock) {

            if (this.file.lastModified() > this.lastModified) {
                try {
                    load(this.file);
                } catch (IOException e) {
                    throw new DataRetrievalFailureException("Error refreshing user file", e);
                }
                return true;
            }
            return false;
        }
    }

    private void load(File file) throws IOException {

        if (file == null) {
            throw new IllegalArgumentException("file may not be null");
        }

        InputStream in = null;
        try {
            in = new FileInputStream(file);
            this.file = file;
            this.lastModified = file.lastModified();
            load(in);
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (Exception e) {
                    logger.warn("Failed to close (??)", e);
                }
            }
        }
    }

    private void load(InputStream stream) throws IOException {
        final BufferedReader reader = new BufferedReader(new InputStreamReader(stream));

        mapByID.clear();
        mapByDN.clear();

        String line;
        while ((line = reader.readLine()) != null) {

            // format is DN accessID secret
            // each token can be quoted and is seperated by whitespace

            line = line.trim();

            if (line.length() == 0 || line.charAt(0) == '#') {
                continue;
            }

            final QuotedStringTokenizer tokenizer = new QuotedStringTokenizer(line, DELIMS);

            final QueryUser user;
            try {
                final String dn = tokenizer.nextToken();
                final String accessID = tokenizer.nextToken();
                final String secret = tokenizer.nextToken();

                user = new QueryUser(accessID, secret, dn);

            } catch (NoSuchElementException e) {
                logger.warn("encountered illegal query user entry in file: '" + line + "'. Ignoring.");
                continue;
            }

            mapByID.put(user.getAccessID(), user);
            mapByDN.put(user.getDn(), user);
        }
    }
}