Coverage Report - org.apache.shiro.realm.text.TextConfigurationRealm
 
Classes in this File Line Coverage Branch Coverage Complexity
TextConfigurationRealm
92%
71/77
75%
27/36
2.923
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *     http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package org.apache.shiro.realm.text;
 20  
 
 21  
 import org.apache.shiro.authc.SimpleAccount;
 22  
 import org.apache.shiro.authz.Permission;
 23  
 import org.apache.shiro.authz.SimpleRole;
 24  
 import org.apache.shiro.config.ConfigurationException;
 25  
 import org.apache.shiro.realm.SimpleAccountRealm;
 26  
 import org.apache.shiro.util.PermissionUtils;
 27  
 import org.apache.shiro.util.StringUtils;
 28  
 
 29  
 import java.text.ParseException;
 30  
 import java.util.*;
 31  
 
 32  
 
 33  
 /**
 34  
  * A SimpleAccountRealm that enables text-based configuration of the initial User, Role, and Permission objects
 35  
  * created at startup.
 36  
  * <p/>
 37  
  * Each User account definition specifies the username, password, and roles for a user.  Each Role definition
 38  
  * specifies a name and an optional collection of assigned Permissions.  Users can be assigned Roles, and Roles can be
 39  
  * assigned Permissions.  By transitive association, each User 'has' all of their Role's Permissions.
 40  
  * <p/>
 41  
  * User and user-to-role definitions are specified via the {@link #setUserDefinitions} method and
 42  
  * Role-to-permission definitions are specified via the {@link #setRoleDefinitions} method.
 43  
  *
 44  
  * @since 0.9
 45  
  */
 46  
 public class TextConfigurationRealm extends SimpleAccountRealm {
 47  
 
 48  
     //TODO - complete JavaDoc
 49  
 
 50  
     private volatile String userDefinitions;
 51  
     private volatile String roleDefinitions;
 52  
 
 53  
     public TextConfigurationRealm() {
 54  62
         super();
 55  62
     }
 56  
 
 57  
     /**
 58  
      * Will call 'processDefinitions' on startup.
 59  
      *
 60  
      * @since 1.2
 61  
      * @see <a href="https://issues.apache.org/jira/browse/SHIRO-223">SHIRO-223</a>
 62  
      */
 63  
     @Override
 64  
     protected void onInit() {
 65  32
         super.onInit();
 66  32
         processDefinitions();
 67  32
     }
 68  
 
 69  
     public String getUserDefinitions() {
 70  36
         return userDefinitions;
 71  
     }
 72  
 
 73  
     /**
 74  
      * <p>Sets a newline (\n) delimited String that defines user-to-password-and-role(s) key/value pairs according
 75  
      * to the following format:
 76  
      * <p/>
 77  
      * <p><code><em>username</em> = <em>password</em>, role1, role2,...</code></p>
 78  
      * <p/>
 79  
      * <p>Here are some examples of what these lines might look like:</p>
 80  
      * <p/>
 81  
      * <p><code>root = <em>reallyHardToGuessPassword</em>, administrator<br/>
 82  
      * jsmith = <em>jsmithsPassword</em>, manager, engineer, employee<br/>
 83  
      * abrown = <em>abrownsPassword</em>, qa, employee<br/>
 84  
      * djones = <em>djonesPassword</em>, qa, contractor<br/>
 85  
      * guest = <em>guestPassword</em></code></p>
 86  
      *
 87  
      * @param userDefinitions the user definitions to be parsed and converted to Map.Entry elements
 88  
      */
 89  
     public void setUserDefinitions(String userDefinitions) {
 90  14
         this.userDefinitions = userDefinitions;
 91  14
     }
 92  
 
 93  
     public String getRoleDefinitions() {
 94  36
         return roleDefinitions;
 95  
     }
 96  
 
 97  
     /**
 98  
      * Sets a newline (\n) delimited String that defines role-to-permission definitions.
 99  
      * <p/>
 100  
      * <p>Each line within the string must define a role-to-permission(s) key/value mapping with the
 101  
      * equals character signifies the key/value separation, like so:</p>
 102  
      * <p/>
 103  
      * <p><code><em>rolename</em> = <em>permissionDefinition1</em>, <em>permissionDefinition2</em>, ...</code></p>
 104  
      * <p/>
 105  
      * <p>where <em>permissionDefinition</em> is an arbitrary String, but must people will want to use
 106  
      * Strings that conform to the {@link org.apache.shiro.authz.permission.WildcardPermission WildcardPermission}
 107  
      * format for ease of use and flexibility.  Note that if an individual <em>permissionDefnition</em> needs to
 108  
      * be internally comma-delimited (e.g. <code>printer:5thFloor:print,info</code>), you will need to surround that
 109  
      * definition with double quotes (&quot;) to avoid parsing errors (e.g.
 110  
      * <code>&quot;printer:5thFloor:print,info&quot;</code>).
 111  
      * <p/>
 112  
      * <p><b>NOTE:</b> if you have roles that don't require permission associations, don't include them in this
 113  
      * definition - just defining the role name in the {@link #setUserDefinitions(String) userDefinitions} is
 114  
      * enough to create the role if it does not yet exist.  This property is really only for configuring realms that
 115  
      * have one or more assigned Permission.
 116  
      *
 117  
      * @param roleDefinitions the role definitions to be parsed at initialization
 118  
      */
 119  
     public void setRoleDefinitions(String roleDefinitions) {
 120  14
         this.roleDefinitions = roleDefinitions;
 121  14
     }
 122  
 
 123  
     protected void processDefinitions() {
 124  
         try {
 125  34
             processRoleDefinitions();
 126  34
             processUserDefinitions();
 127  0
         } catch (ParseException e) {
 128  0
             String msg = "Unable to parse user and/or role definitions.";
 129  0
             throw new ConfigurationException(msg, e);
 130  34
         }
 131  34
     }
 132  
 
 133  
     protected void processRoleDefinitions() throws ParseException {
 134  36
         String roleDefinitions = getRoleDefinitions();
 135  36
         if (roleDefinitions == null) {
 136  22
             return;
 137  
         }
 138  14
         Map<String, String> roleDefs = toMap(toLines(roleDefinitions));
 139  14
         processRoleDefinitions(roleDefs);
 140  14
     }
 141  
 
 142  
     protected void processRoleDefinitions(Map<String, String> roleDefs) {
 143  22
         if (roleDefs == null || roleDefs.isEmpty()) {
 144  0
             return;
 145  
         }
 146  22
         for (String rolename : roleDefs.keySet()) {
 147  34
             String value = roleDefs.get(rolename);
 148  
 
 149  34
             SimpleRole role = getRole(rolename);
 150  34
             if (role == null) {
 151  34
                 role = new SimpleRole(rolename);
 152  34
                 add(role);
 153  
             }
 154  
 
 155  34
             Set<Permission> permissions = PermissionUtils.resolveDelimitedPermissions(value, getPermissionResolver());
 156  34
             role.setPermissions(permissions);
 157  34
         }
 158  22
     }
 159  
 
 160  
     protected void processUserDefinitions() throws ParseException {
 161  36
         String userDefinitions = getUserDefinitions();
 162  36
         if (userDefinitions == null) {
 163  22
             return;
 164  
         }
 165  
 
 166  14
         Map<String, String> userDefs = toMap(toLines(userDefinitions));
 167  
 
 168  14
         processUserDefinitions(userDefs);
 169  14
     }
 170  
 
 171  
     protected void processUserDefinitions(Map<String, String> userDefs) {
 172  52
         if (userDefs == null || userDefs.isEmpty()) {
 173  0
             return;
 174  
         }
 175  52
         for (String username : userDefs.keySet()) {
 176  
 
 177  74
             String value = userDefs.get(username);
 178  
 
 179  74
             String[] passwordAndRolesArray = StringUtils.split(value);
 180  
 
 181  74
             String password = passwordAndRolesArray[0];
 182  
 
 183  74
             SimpleAccount account = getUser(username);
 184  74
             if (account == null) {
 185  74
                 account = new SimpleAccount(username, password, getName());
 186  74
                 add(account);
 187  
             }
 188  74
             account.setCredentials(password);
 189  
 
 190  74
             if (passwordAndRolesArray.length > 1) {
 191  128
                 for (int i = 1; i < passwordAndRolesArray.length; i++) {
 192  76
                     String rolename = passwordAndRolesArray[i];
 193  76
                     account.addRole(rolename);
 194  
 
 195  76
                     SimpleRole role = getRole(rolename);
 196  76
                     if (role != null) {
 197  48
                         account.addObjectPermissions(role.getPermissions());
 198  
                     }
 199  
                 }
 200  
             } else {
 201  22
                 account.setRoles(null);
 202  
             }
 203  74
         }
 204  52
     }
 205  
 
 206  
     protected static Set<String> toLines(String s) {
 207  28
         LinkedHashSet<String> set = new LinkedHashSet<String>();
 208  28
         Scanner scanner = new Scanner(s);
 209  80
         while (scanner.hasNextLine()) {
 210  52
             set.add(scanner.nextLine());
 211  
         }
 212  28
         return set;
 213  
     }
 214  
 
 215  
     protected static Map<String, String> toMap(Collection<String> keyValuePairs) throws ParseException {
 216  28
         if (keyValuePairs == null || keyValuePairs.isEmpty()) {
 217  0
             return null;
 218  
         }
 219  
 
 220  28
         Map<String, String> pairs = new HashMap<String, String>();
 221  28
         for (String pairString : keyValuePairs) {
 222  52
             String[] pair = StringUtils.splitKeyValue(pairString);
 223  52
             if (pair != null) {
 224  52
                 pairs.put(pair[0].trim(), pair[1].trim());
 225  
             }
 226  52
         }
 227  
 
 228  28
         return pairs;
 229  
     }
 230  
 }