/*
 * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.jmx.remote.security;

import java.io.FileInputStream;
import java.io.IOException;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.regex.Pattern;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.security.auth.Subject;

/**
 * <p>An object of this class implements the MBeanServerAccessController
 * interface and, for each of its methods, calls an appropriate checking
 * method and then forwards the request to a wrapped MBeanServer object.
 * The checking method may throw a SecurityException if the operation is
 * not allowed; in this case the request is not forwarded to the
 * wrapped object.</p>
 *
 * <p>This class implements the {@link #checkRead()}, {@link #checkWrite()},
 * {@link #checkCreate(String)}, and {@link #checkUnregister(ObjectName)}
 * methods based on an access level properties file containing username/access
 * level pairs. The set of username/access level pairs is passed either as a
 * filename which denotes a properties file on disk, or directly as an instance
 * of the {@link Properties} class.  In both cases, the name of each property
 * represents a username, and the value of the property is the associated access
 * level.  Thus, any given username either does not exist in the properties or
 * has exactly one access level. The same access level can be shared by several
 * usernames.</p>
 *
 * <p>The supported access level values are {@code readonly} and
 * {@code readwrite}.  The {@code readwrite} access level can be
 * qualified by one or more <i>clauses</i>, where each clause looks
 * like <code>create <i>classNamePattern</i></code> or {@code
 * unregister}.  For example:</p>
 *
 * <pre>
 * monitorRole  readonly
 * controlRole  readwrite \
 *              create javax.management.timer.*,javax.management.monitor.* \
 *              unregister
 * </pre>
 *
 * <p>(The continuation lines with {@code \} come from the parser for
 * Properties files.)</p>
 */
public class MBeanServerFileAccessController
    extends MBeanServerAccessController {

    static final String READONLY = "readonly";
    static final String READWRITE = "readwrite";

    static final String CREATE = "create";
    static final String UNREGISTER = "unregister";

    private enum AccessType {READ, WRITE, CREATE, UNREGISTER};

    private static class Access {
        final boolean write;
        final String[] createPatterns;
        private boolean unregister;

        Access(boolean write, boolean unregister, List<String> createPatternList) {
            this.write = write;
            int npats = (createPatternList == null) ? 0 : createPatternList.size();
            if (npats == 0)
                this.createPatterns = NO_STRINGS;
            else
                this.createPatterns = createPatternList.toArray(new String[npats]);
            this.unregister = unregister;
        }

        private final String[] NO_STRINGS = new String[0];
    }

    /**
     * <p>Create a new MBeanServerAccessController that forwards all the
     * MBeanServer requests to the MBeanServer set by invoking the {@link
     * #setMBeanServer} method after doing access checks based on read and
     * write permissions.</p>
     *
     * <p>This instance is initialized from the specified properties file.</p>
     *
     * @param accessFileName name of the file which denotes a properties
     * file on disk containing the username/access level entries.
     *
     * @exception IOException if the file does not exist, is a
     * directory rather than a regular file, or for some other
     * reason cannot be opened for reading.
     *
     * @exception IllegalArgumentException if any of the supplied access
     * level values differs from "readonly" or "readwrite".
     */
    public MBeanServerFileAccessController(String accessFileName)
        throws IOException {
        super();
        this.accessFileName = accessFileName;
        Properties props = propertiesFromFile(accessFileName);
        parseProperties(props);
    }

    /**
     * <p>Create a new MBeanServerAccessController that forwards all the
     * MBeanServer requests to <code>mbs</code> after doing access checks
     * based on read and write permissions.</p>
     *
     * <p>This instance is initialized from the specified properties file.</p>
     *
     * @param accessFileName name of the file which denotes a properties
     * file on disk containing the username/access level entries.
     *
     * @param mbs the MBeanServer object to which requests will be forwarded.
     *
     * @exception IOException if the file does not exist, is a
     * directory rather than a regular file, or for some other
     * reason cannot be opened for reading.
     *
     * @exception IllegalArgumentException if any of the supplied access
     * level values differs from "readonly" or "readwrite".
     */
    public MBeanServerFileAccessController(String accessFileName,
                                           MBeanServer mbs)
        throws IOException {
        this(accessFileName);
        setMBeanServer(mbs);
    }

    /**
     * <p>Create a new MBeanServerAccessController that forwards all the
     * MBeanServer requests to the MBeanServer set by invoking the {@link
     * #setMBeanServer} method after doing access checks based on read and
     * write permissions.</p>
     *
     * <p>This instance is initialized from the specified properties
     * instance.  This constructor makes a copy of the properties
     * instance and it is the copy that is consulted to check the
     * username and access level of an incoming connection. The
     * original properties object can be modified without affecting
     * the copy. If the {@link #refresh} method is then called, the
     * <code>MBeanServerFileAccessController</code> will make a new
     * copy of the properties object at that time.</p>
     *
     * @param accessFileProps properties list containing the username/access
     * level entries.
     *
     * @exception IllegalArgumentException if <code>accessFileProps</code> is
     * <code>null</code> or if any of the supplied access level values differs
     * from "readonly" or "readwrite".
     */
    public MBeanServerFileAccessController(Properties accessFileProps)
        throws IOException {
        super();
        if (accessFileProps == null)
            throw new IllegalArgumentException("Null properties");
        originalProps = accessFileProps;
        parseProperties(accessFileProps);
    }

    /**
     * <p>Create a new MBeanServerAccessController that forwards all the
     * MBeanServer requests to the MBeanServer set by invoking the {@link
     * #setMBeanServer} method after doing access checks based on read and
     * write permissions.</p>
     *
     * <p>This instance is initialized from the specified properties
     * instance.  This constructor makes a copy of the properties
     * instance and it is the copy that is consulted to check the
     * username and access level of an incoming connection. The
     * original properties object can be modified without affecting
     * the copy. If the {@link #refresh} method is then called, the
     * <code>MBeanServerFileAccessController</code> will make a new
     * copy of the properties object at that time.</p>
     *
     * @param accessFileProps properties list containing the username/access
     * level entries.
     *
     * @param mbs the MBeanServer object to which requests will be forwarded.
     *
     * @exception IllegalArgumentException if <code>accessFileProps</code> is
     * <code>null</code> or if any of the supplied access level values differs
     * from "readonly" or "readwrite".
     */
    public MBeanServerFileAccessController(Properties accessFileProps,
                                           MBeanServer mbs)
        throws IOException {
        this(accessFileProps);
        setMBeanServer(mbs);
    }

    /**
     * Check if the caller can do read operations. This method does
     * nothing if so, otherwise throws SecurityException.
     */
    @Override
    public void checkRead() {
        checkAccess(AccessType.READ, null);
    }

    /**
     * Check if the caller can do write operations.  This method does
     * nothing if so, otherwise throws SecurityException.
     */
    @Override
    public void checkWrite() {
        checkAccess(AccessType.WRITE, null);
    }

    /**
     * Check if the caller can create MBeans or instances of the given class.
     * This method does nothing if so, otherwise throws SecurityException.
     */
    @Override
    public void checkCreate(String className) {
        checkAccess(AccessType.CREATE, className);
    }

    /**
     * Check if the caller can do unregister operations.  This method does
     * nothing if so, otherwise throws SecurityException.
     */
    @Override
    public void checkUnregister(ObjectName name) {
        checkAccess(AccessType.UNREGISTER, null);
    }

    /**
     * <p>Refresh the set of username/access level entries.</p>
     *
     * <p>If this instance was created using the
     * {@link #MBeanServerFileAccessController(String)} or
     * {@link #MBeanServerFileAccessController(String,MBeanServer)}
     * constructors to specify a file from which the entries are read,
     * the file is re-read.</p>
     *
     * <p>If this instance was created using the
     * {@link #MBeanServerFileAccessController(Properties)} or
     * {@link #MBeanServerFileAccessController(Properties,MBeanServer)}
     * constructors then a new copy of the <code>Properties</code> object
     * is made.</p>
     *
     * @exception IOException if the file does not exist, is a
     * directory rather than a regular file, or for some other
     * reason cannot be opened for reading.
     *
     * @exception IllegalArgumentException if any of the supplied access
     * level values differs from "readonly" or "readwrite".
     */
    public synchronized void refresh() throws IOException {
        Properties props;
        if (accessFileName == null)
            props = (Properties) originalProps;
        else
            props = propertiesFromFile(accessFileName);
        parseProperties(props);
    }

    private static Properties propertiesFromFile(String fname)
        throws IOException {
        FileInputStream fin = new FileInputStream(fname);
        try {
            Properties p = new Properties();
            p.load(fin);
            return p;
        } finally {
            fin.close();
        }
    }

    private synchronized void checkAccess(AccessType requiredAccess, String arg) {
        final AccessControlContext acc = AccessController.getContext();
        final Subject s =
            AccessController.doPrivileged(new PrivilegedAction<Subject>() {
                    public Subject run() {
                        return Subject.getSubject(acc);
                    }
                });
        if (s == null) return; /* security has not been enabled */
        final Set principals = s.getPrincipals();
        String newPropertyValue = null;
        for (Iterator i = principals.iterator(); i.hasNext(); ) {
            final Principal p = (Principal) i.next();
            Access access = accessMap.get(p.getName());
            if (access != null) {
                boolean ok;
                switch (requiredAccess) {
                    case READ:
                        ok = true;  // all access entries imply read
                        break;
                    case WRITE:
                        ok = access.write;
                        break;
                    case UNREGISTER:
                        ok = access.unregister;
                        if (!ok && access.write)
                            newPropertyValue = "unregister";
                        break;
                    case CREATE:
                        ok = checkCreateAccess(access, arg);
                        if (!ok && access.write)
                            newPropertyValue = "create " + arg;
                        break;
                    default:
                        throw new AssertionError();
                }
                if (ok)
                    return;
            }
        }
        SecurityException se = new SecurityException("Access denied! Invalid " +
                "access level for requested MBeanServer operation.");
        // Add some more information to help people with deployments that
        // worked before we required explicit create clauses. We're not giving
        // any information to the bad guys, other than that the access control
        // is based on a file, which they could have worked out from the stack
        // trace anyway.
        if (newPropertyValue != null) {
            SecurityException se2 = new SecurityException("Access property " +
                    "for this identity should be similar to: " + READWRITE +
                    " " + newPropertyValue);
            se.initCause(se2);
        }
        throw se;
    }

    private static boolean checkCreateAccess(Access access, String className) {
        for (String classNamePattern : access.createPatterns) {
            if (classNameMatch(classNamePattern, className))
                return true;
        }
        return false;
    }

    private static boolean classNameMatch(String pattern, String className) {
        // We studiously avoided regexes when parsing the properties file,
        // because that is done whenever the VM is started with the
        // appropriate -Dcom.sun.management options, even if nobody ever
        // creates an MBean.  We don't want to incur the overhead of loading
        // all the regex code whenever those options are specified, but if we
        // get as far as here then the VM is already running and somebody is
        // doing the very unusual operation of remotely creating an MBean.
        // Because that operation is so unusual, we don't try to optimize
        // by hand-matching or by caching compiled Pattern objects.
        StringBuilder sb = new StringBuilder();
        StringTokenizer stok = new StringTokenizer(pattern, "*", true);
        while (stok.hasMoreTokens()) {
            String tok = stok.nextToken();
            if (tok.equals("*"))
                sb.append("[^.]*");
            else
                sb.append(Pattern.quote(tok));
        }
        return className.matches(sb.toString());
    }

    private void parseProperties(Properties props) {
        this.accessMap = new HashMap<String, Access>();
        for (Map.Entry<Object, Object> entry : props.entrySet()) {
            String identity = (String) entry.getKey();
            String accessString = (String) entry.getValue();
            Access access = Parser.parseAccess(identity, accessString);
            accessMap.put(identity, access);
        }
    }

    private static class Parser {
        private final static int EOS = -1;  // pseudo-codepoint "end of string"
        static {
            assert !Character.isWhitespace(EOS);
        }

        private final String identity;  // just for better error messages
        private final String s;  // the string we're parsing
        private final int len;   // s.length()
        private int i;
        private int c;
        // At any point, either c is s.codePointAt(i), or i == len and
        // c is EOS.  We use int rather than char because it is conceivable
        // (if unlikely) that a classname in a create clause might contain
        // "supplementary characters", the ones that don't fit in the original
        // 16 bits for Unicode.

        private Parser(String identity, String s) {
            this.identity = identity;
            this.s = s;
            this.len = s.length();
            this.i = 0;
            if (i < len)
                this.c = s.codePointAt(i);
            else
                this.c = EOS;
        }

        static Access parseAccess(String identity, String s) {
            return new Parser(identity, s).parseAccess();
        }

        private Access parseAccess() {
            skipSpace();
            String type = parseWord();
            Access access;
            if (type.equals(READONLY))
                access = new Access(false, false, null);
            else if (type.equals(READWRITE))
                access = parseReadWrite();
            else {
                throw syntax("Expected " + READONLY + " or " + READWRITE +
                        ": " + type);
            }
            if (c != EOS)
                throw syntax("Extra text at end of line");
            return access;
        }

        private Access parseReadWrite() {
            List<String> createClasses = new ArrayList<String>();
            boolean unregister = false;
            while (true) {
                skipSpace();
                if (c == EOS)
                    break;
                String type = parseWord();
                if (type.equals(UNREGISTER))
                    unregister = true;
                else if (type.equals(CREATE))
                    parseCreate(createClasses);
                else
                    throw syntax("Unrecognized keyword " + type);
            }
            return new Access(true, unregister, createClasses);
        }

        private void parseCreate(List<String> createClasses) {
            while (true) {
                skipSpace();
                createClasses.add(parseClassName());
                skipSpace();
                if (c == ',')
                    next();
                else
                    break;
            }
        }

        private String parseClassName() {
            // We don't check that classname components begin with suitable
            // characters (so we accept 1.2.3 for example).  This means that
            // there are only two states, which we can call dotOK and !dotOK
            // according as a dot (.) is legal or not.  Initially we're in
            // !dotOK since a classname can't start with a dot; after a dot
            // we're in !dotOK again; and after any other characters we're in
            // dotOK.  The classname is only accepted if we end in dotOK,
            // so we reject an empty name or a name that ends with a dot.
            final int start = i;
            boolean dotOK = false;
            while (true) {
                if (c == '.') {
                    if (!dotOK)
                        throw syntax("Bad . in class name");
                    dotOK = false;
                } else if (c == '*' || Character.isJavaIdentifierPart(c))
                    dotOK = true;
                else
                    break;
                next();
            }
            String className = s.substring(start, i);
            if (!dotOK)
                throw syntax("Bad class name " + className);
            return className;
        }

        // Advance c and i to the next character, unless already at EOS.
        private void next() {
            if (c != EOS) {
                i += Character.charCount(c);
                if (i < len)
                    c = s.codePointAt(i);
                else
                    c = EOS;
            }
        }

        private void skipSpace() {
            while (Character.isWhitespace(c))
                next();
        }

        private String parseWord() {
            skipSpace();
            if (c == EOS)
                throw syntax("Expected word at end of line");
            final int start = i;
            while (c != EOS && !Character.isWhitespace(c))
                next();
            String word = s.substring(start, i);
            skipSpace();
            return word;
        }

        private IllegalArgumentException syntax(String msg) {
            return new IllegalArgumentException(
                    msg + " [" + identity + " " + s + "]");
        }
    }

    private Map<String, Access> accessMap;
    private Properties originalProps;
    private String accessFileName;
}
