001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019 package org.apache.shiro.realm;
020
021 import org.apache.shiro.authc.*;
022 import org.apache.shiro.authz.AuthorizationInfo;
023 import org.apache.shiro.authz.SimpleRole;
024 import org.apache.shiro.subject.PrincipalCollection;
025 import org.apache.shiro.util.CollectionUtils;
026
027 import java.util.HashSet;
028 import java.util.LinkedHashMap;
029 import java.util.Map;
030 import java.util.Set;
031
032 /**
033 * A simple implementation of the {@link Realm Realm} interface that
034 * uses a set of configured user accounts and roles to support authentication and authorization. Each account entry
035 * specifies the username, password, and roles for a user. Roles can also be mapped
036 * to permissions and associated with users.
037 * <p/>
038 * User accounts and roles are stored in two {@code Map}s in memory, so it is expected that the total number of either
039 * is not sufficiently large.
040 *
041 * @author Jeremy Haile
042 * @author Les Hazlewood
043 * @since 0.1
044 */
045 public class SimpleAccountRealm extends AuthorizingRealm {
046
047 //TODO - complete JavaDoc
048
049 protected final Map<String, SimpleAccount> users; //username-to-SimpleAccount
050 protected final Map<String, SimpleRole> roles; //roleName-to-SimpleRole
051
052 public SimpleAccountRealm() {
053 this.users = new LinkedHashMap<String, SimpleAccount>();
054 this.roles = new LinkedHashMap<String, SimpleRole>();
055 //SimpleAccountRealms are memory-only realms - no need for an additional cache mechanism since we're
056 //already as memory-efficient as we can be:
057 setCachingEnabled(false);
058 }
059
060 public SimpleAccountRealm(String name) {
061 this();
062 setName(name);
063 }
064
065 protected SimpleAccount getUser(String username) {
066 return this.users.get(username);
067 }
068
069 public boolean accountExists(String username) {
070 return getUser(username) != null;
071 }
072
073 public void addAccount(String username, String password) {
074 addAccount(username, password, (String[]) null);
075 }
076
077 public void addAccount(String username, String password, String... roles) {
078 Set<String> roleNames = CollectionUtils.asSet(roles);
079 SimpleAccount account = new SimpleAccount(username, password, getName(), roleNames, null);
080 add(account);
081 }
082
083 protected String getUsername(SimpleAccount account) {
084 return getUsername(account.getPrincipals());
085 }
086
087 protected String getUsername(PrincipalCollection principals) {
088 return getAvailablePrincipal(principals).toString();
089 }
090
091 protected void add(SimpleAccount account) {
092 String username = getUsername(account);
093 this.users.put(username, account);
094 }
095
096 protected SimpleRole getRole(String rolename) {
097 return roles.get(rolename);
098 }
099
100 public boolean roleExists(String name) {
101 return getRole(name) != null;
102 }
103
104 public void addRole(String name) {
105 add(new SimpleRole(name));
106 }
107
108 protected void add(SimpleRole role) {
109 roles.put(role.getName(), role);
110 }
111
112 protected static Set<String> toSet(String delimited, String delimiter) {
113 if (delimited == null || delimited.trim().equals("")) {
114 return null;
115 }
116
117 Set<String> values = new HashSet<String>();
118 String[] rolenamesArray = delimited.split(delimiter);
119 for (String s : rolenamesArray) {
120 String trimmed = s.trim();
121 if (trimmed.length() > 0) {
122 values.add(trimmed);
123 }
124 }
125
126 return values;
127 }
128
129 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
130 UsernamePasswordToken upToken = (UsernamePasswordToken) token;
131 SimpleAccount account = getUser(upToken.getUsername());
132
133 if (account != null) {
134
135 if (account.isLocked()) {
136 throw new LockedAccountException("Account [" + account + "] is locked.");
137 }
138 if (account.isCredentialsExpired()) {
139 String msg = "The credentials for account [" + account + "] are expired";
140 throw new ExpiredCredentialsException(msg);
141 }
142
143 }
144
145 return account;
146 }
147
148 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
149 return this.users.get(getUsername(principals));
150 }
151 }