com.caricah.iotracah.bootstrap.security.realm.impl.IOTTextConfiguredRealm.java Source code

Java tutorial

Introduction

Here is the source code for com.caricah.iotracah.bootstrap.security.realm.impl.IOTTextConfiguredRealm.java

Source

/*
 *
 * Copyright (c) 2015 Caricah <info@caricah.com>.
 *
 * Caricah licenses this file to you 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 com.caricah.iotracah.bootstrap.security.realm.impl;

import com.caricah.iotracah.bootstrap.security.realm.IOTAbstractRealm;
import com.caricah.iotracah.bootstrap.security.realm.auth.permission.IOTPermission;
import com.caricah.iotracah.bootstrap.security.realm.state.IOTAccount;
import com.caricah.iotracah.bootstrap.security.realm.state.IOTRole;
import org.apache.shiro.authz.Permission;
import org.apache.shiro.config.ConfigurationException;
import org.apache.shiro.util.PermissionUtils;
import org.apache.shiro.util.StringUtils;

import java.text.ParseException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author <a href="mailto:bwire@caricah.com"> Peter Bwire </a>
 * @version 1.0 10/6/15
 */
public class IOTTextConfiguredRealm extends IOTAbstractRealm {

    private final Pattern usernamePartitionPattern = Pattern.compile("(?<username>.*)-<(?<partition>.*)>");
    private final Pattern rolePartitionPattern = Pattern.compile("(?<rolename>.*)-<(?<partition>.*)>");

    private volatile String userDefinitions;
    private volatile String roleDefinitions;

    private String defaultPartitionName;

    public String getDefaultPartitionName() {
        return defaultPartitionName;
    }

    public void setDefaultPartitionName(String defaultPartitionName) {
        this.defaultPartitionName = defaultPartitionName;
    }

    /**
     * Will call 'processDefinitions' on startup.
     *
     * @see <a href="https://issues.apache.org/jira/browse/SHIRO-223">SHIRO-223</a>
     * @since 1.2
     */
    @Override
    protected void onInit() {
        super.onInit();
        processDefinitions();
    }

    public String getUserDefinitions() {
        return userDefinitions;
    }

    /**
     * <p>Sets a newline (\n) delimited String that defines user-to-password-and-role(s) key/value pairs according
     * to the following format:
     * <p/>
     * <p><code><em>username</em> = <em>password</em>, role1, role2,...</code></p>
     * <p/>
     * <p>Here are some examples of what these lines might look like:</p>
     * <p/>
     * <p><code>root = <em>reallyHardToGuessPassword</em>, administrator<br/>
     * jsmith = <em>jsmithsPassword</em>, manager, engineer, employee<br/>
     * abrown = <em>abrownsPassword</em>, qa, employee<br/>
     * djones = <em>djonesPassword</em>, qa, contractor<br/>
     * guest = <em>guestPassword</em></code></p>
     *
     * @param userDefinitions the user definitions to be parsed and converted to Map.Entry elements
     */
    public void setUserDefinitions(String userDefinitions) {
        this.userDefinitions = userDefinitions;
    }

    public String getRoleDefinitions() {
        return roleDefinitions;
    }

    /**
     * Sets a newline (\n) delimited String that defines role-to-permission definitions.
     * <p/>
     * <p>Each line within the string must define a role-to-permission(s) key/value mapping with the
     * equals character signifies the key/value separation, like so:</p>
     * <p/>
     * <p><code><em>rolename</em> = <em>permissionDefinition1</em>, <em>permissionDefinition2</em>, ...</code></p>
     * <p>
     * <p>where <em>permissionDefinition</em> is an arbitrary String, but must people will want to use
     * Strings that conform to the {@link org.apache.shiro.authz.permission.WildcardPermission WildcardPermission}
     * format for ease of use and flexibility.  Note that if an individual <em>permissionDefnition</em> needs to
     * be internally comma-delimited (e.g. <code>printer:5thFloor:print,info</code>), you will need to surround that
     * definition with double quotes (&quot;) to avoid parsing errors (e.g.
     * <code>&quot;printer:5thFloor:print,info&quot;</code>).
     * <p>
     * <p><b>NOTE:</b> if you have roles that don't require permission associations, don't include them in this
     * definition - just defining the role name in the {@link #setUserDefinitions(String) userDefinitions} is
     * enough to create the role if it does not yet exist.  This property is really only for configuring realms that
     * have one or more assigned Permission.
     *
     * @param roleDefinitions the role definitions to be parsed at initialization
     */
    public void setRoleDefinitions(String roleDefinitions) {
        this.roleDefinitions = roleDefinitions;
    }

    protected void processDefinitions() {
        try {
            processRoleDefinitions();
            processUserDefinitions();
        } catch (ParseException e) {
            String msg = "Unable to parse user and/or role definitions.";
            throw new ConfigurationException(msg, e);
        }
    }

    protected void processRoleDefinitions() throws ParseException {
        String roleDefinitions = getRoleDefinitions();
        if (roleDefinitions == null) {
            return;
        }
        Map<String, String> roleDefs = toMap(toLines(roleDefinitions));
        processRoleDefinitions(roleDefs);
    }

    protected void processRoleDefinitions(Map<String, String> roleDefs) {
        if (roleDefs == null || roleDefs.isEmpty()) {
            return;
        }
        for (String rolename : roleDefs.keySet()) {

            String value = roleDefs.get(rolename);

            //Parse the rolename for partition.
            String partition;

            Matcher matcher = rolePartitionPattern.matcher(rolename);
            if (matcher.matches()) {
                partition = matcher.group("partition");
                rolename = matcher.group("rolename");
            } else {
                partition = getDefaultPartitionName();
            }

            IOTRole role = getIOTRole(partition, rolename);
            if (role == null) {
                role = addIOTRole(partition, rolename);

            }

            Set<Permission> permissions = PermissionUtils.resolveDelimitedPermissions(value,
                    getPermissionResolver());

            for (Permission permission : permissions) {
                role.add((IOTPermission) permission);
            }

            saveIOTRole(role);
        }
    }

    protected void processUserDefinitions() throws ParseException {
        String userDefinitions = getUserDefinitions();
        if (userDefinitions == null) {
            return;
        }

        Map<String, String> userDefs = toMap(toLines(userDefinitions));

        processUserDefinitions(userDefs);
    }

    protected void processUserDefinitions(Map<String, String> userDefs) {
        if (userDefs == null || userDefs.isEmpty()) {
            return;
        }
        for (String username : userDefs.keySet()) {

            String value = userDefs.get(username);

            String[] passwordAndRolesArray = StringUtils.split(value);

            String password = passwordAndRolesArray[0];

            String partition;
            Matcher matcher = usernamePartitionPattern.matcher(username);
            if (matcher.matches()) {
                partition = matcher.group("partition");
                username = matcher.group("username");
            } else {
                partition = getDefaultPartitionName();
            }

            if (Objects.nonNull(username) && !username.isEmpty()) {
                IOTAccount account = getIOTAccount(partition, username);
                if (account == null) {

                    account = addIOTAccount(partition, username, password);
                }
                account.setCredential(password);

                if (passwordAndRolesArray.length > 1) {
                    for (int i = 1; i < passwordAndRolesArray.length; i++) {
                        String rolename = passwordAndRolesArray[i];
                        account.addRole(rolename);
                    }
                }

                saveIOTAccount(account);
            }
        }
    }

    protected static Set<String> toLines(String s) {
        LinkedHashSet<String> set = new LinkedHashSet<String>();
        Scanner scanner = new Scanner(s);
        while (scanner.hasNextLine()) {
            set.add(scanner.nextLine());
        }
        return set;
    }

    protected static Map<String, String> toMap(Collection<String> keyValuePairs) throws ParseException {
        if (keyValuePairs == null || keyValuePairs.isEmpty()) {
            return null;
        }

        Map<String, String> pairs = new HashMap<String, String>();
        for (String pairString : keyValuePairs) {
            String[] pair = StringUtils.splitKeyValue(pairString);
            if (pair != null) {
                pairs.put(pair[0].trim(), pair[1].trim());
            }
        }

        return pairs;
    }

}