| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF 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 org.jsecurity.realm.text; |
| |
| import org.jsecurity.authc.SimpleAccount; |
| import org.jsecurity.authz.Permission; |
| import org.jsecurity.authz.SimpleRole; |
| import org.jsecurity.realm.SimpleAccountRealm; |
| import org.jsecurity.subject.PrincipalCollection; |
| import org.jsecurity.util.PermissionUtils; |
| import org.jsecurity.util.StringUtils; |
| |
| import java.text.ParseException; |
| import java.util.*; |
| |
| /** |
| * <p>a SimpleAccountRealm that enables text-based configuration of the initial User, Role, and Permission objects |
| * created at startup. |
| * |
| * <p>Each User account definition specifies the username, password, and roles for a user. Each Role definition |
| * specifies a name and an optional collection of assigned Permissions. Users can be assigned Roles, and Roles can be |
| * assigned Permissions. By transitive association, each User 'has' all of their Role's Permissions.</p> |
| * |
| * <p>User and user-to-role definitinos are specified via the {@link #setUserDefinitions} method and |
| * Role-to-permission definitions are specified via the {@link #setRoleDefinitions} method. |
| * |
| * @author Les Hazlewood |
| * @since 0.9 |
| */ |
| public class TextConfigurationRealm extends SimpleAccountRealm { |
| |
| //TODO - complete JavaDoc |
| |
| private String userDefinitions; |
| private String roleDefinitions; |
| |
| public TextConfigurationRealm() { |
| } |
| |
| 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><code><em>username</em> = <em>password</em>, role1, role2,...</code></p> |
| * |
| * <p>Here are some examples of what these lines might look like:</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>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><code><em>rolename</em> = <em>permissionDefinition1</em>, <em>permissionDefinition2</em>, ...</code></p> |
| * |
| * <p>where <em>permissionDefinition</em> is an arbitrary String, but must people will want to use |
| * Strings that conform to the {@link org.jsecurity.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 (") to avoid parsing errors (e.g. |
| * <code>"printer:5thFloor:print,info"</code>). |
| * |
| * <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 accountAndRoleCachesCreated() { |
| processDefinitions(); |
| } |
| |
| protected void processDefinitions() { |
| try { |
| processRoleDefinitions(); |
| processUserDefinitions(); |
| } catch (ParseException e) { |
| String msg = "Unable to parse user and/or role definitions."; |
| throw new IllegalStateException(msg, e); |
| } |
| } |
| |
| protected void processRoleDefinitions() throws ParseException { |
| String roleDefinitions = getRoleDefinitions(); |
| if (roleDefinitions == null) { |
| return; |
| } |
| Map<String, String> roleDefs = toMap(toLines(roleDefinitions)); |
| if (roleDefs == null || roleDefs.isEmpty()) { |
| return; |
| } |
| |
| for (String rolename : roleDefs.keySet()) { |
| String value = roleDefs.get(rolename); |
| |
| SimpleRole role = getRole(rolename); |
| if (role == null) { |
| role = new SimpleRole(rolename); |
| add(role); |
| } |
| |
| Set<Permission> permissions = PermissionUtils.resolveDelimitedPermissions(value, getPermissionResolver()); |
| role.setPermissions(permissions); |
| } |
| } |
| |
| protected void processUserDefinitions() throws ParseException { |
| |
| String userDefinitions = getUserDefinitions(); |
| if (userDefinitions == null) { |
| return; |
| } |
| |
| Map<String, String> userDefs = toMap(toLines(userDefinitions)); |
| 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]; |
| |
| SimpleAccount account = getUser(username); |
| if (account == null) { |
| account = new SimpleAccount(username, password, getName()); |
| add(account); |
| } |
| account.setCredentials(password); |
| |
| if (passwordAndRolesArray.length > 1) { |
| for (int i = 1; i < passwordAndRolesArray.length; i++) { |
| String rolename = passwordAndRolesArray[i]; |
| account.addRole(rolename); |
| |
| SimpleRole role = getRole(rolename); |
| if (role != null) { |
| account.addObjectPermissions(role.getPermissions()); |
| } |
| } |
| } else { |
| account.setRoles(null); |
| } |
| } |
| } |
| |
| 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; |
| } |
| |
| public void onLogout(PrincipalCollection accountPrincipal) { |
| //override parent method of removing user from cache |
| //we don't want that to happen on cache-only realm since that would permanently |
| //remove the user from the realm. |
| } |
| } |