View Javadoc
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;
20  
21  import org.apache.shiro.authc.AuthenticationException;
22  import org.apache.shiro.authc.AuthenticationInfo;
23  import org.apache.shiro.authc.AuthenticationToken;
24  import org.apache.shiro.authc.ExpiredCredentialsException;
25  import org.apache.shiro.authc.LockedAccountException;
26  import org.apache.shiro.authc.SimpleAccount;
27  import org.apache.shiro.authc.UsernamePasswordToken;
28  import org.apache.shiro.authz.AuthorizationInfo;
29  import org.apache.shiro.authz.SimpleRole;
30  import org.apache.shiro.subject.PrincipalCollection;
31  import org.apache.shiro.util.CollectionUtils;
32  
33  import java.util.HashSet;
34  import java.util.LinkedHashMap;
35  import java.util.Map;
36  import java.util.Set;
37  import java.util.concurrent.locks.ReadWriteLock;
38  import java.util.concurrent.locks.ReentrantReadWriteLock;
39  
40  /**
41   * A simple implementation of the {@link Realm Realm} interface that
42   * uses a set of configured user accounts and roles to support authentication and authorization.  Each account entry
43   * specifies the username, password, and roles for a user.  Roles can also be mapped
44   * to permissions and associated with users.
45   * <p/>
46   * User accounts and roles are stored in two {@code Map}s in memory, so it is expected that the total number of either
47   * is not sufficiently large.
48   *
49   * @since 0.1
50   */
51  public class SimpleAccountRealm extends AuthorizingRealm {
52  
53      //TODO - complete JavaDoc
54      protected final Map<String, SimpleAccount> users; //username-to-SimpleAccount
55      protected final Map<String, SimpleRole> roles; //roleName-to-SimpleRole
56      protected final ReadWriteLock USERS_LOCK;
57      protected final ReadWriteLock ROLES_LOCK;
58  
59      public SimpleAccountRealm() {
60          this.users = new LinkedHashMap<String, SimpleAccount>();
61          this.roles = new LinkedHashMap<String, SimpleRole>();
62          USERS_LOCK = new ReentrantReadWriteLock();
63          ROLES_LOCK = new ReentrantReadWriteLock();
64          //SimpleAccountRealms are memory-only realms - no need for an additional cache mechanism since we're
65          //already as memory-efficient as we can be:
66          setCachingEnabled(false);
67      }
68  
69      public SimpleAccountRealm(String name) {
70          this();
71          setName(name);
72      }
73  
74      protected SimpleAccount getUser(String username) {
75          USERS_LOCK.readLock().lock();
76          try {
77              return this.users.get(username);
78          } finally {
79              USERS_LOCK.readLock().unlock();
80          }
81      }
82  
83      public boolean accountExists(String username) {
84          return getUser(username) != null;
85      }
86  
87      public void addAccount(String username, String password) {
88          addAccount(username, password, (String[]) null);
89      }
90  
91      public void addAccount(String username, String password, String... roles) {
92          Set<String> roleNames = CollectionUtils.asSet(roles);
93          SimpleAccount account = new SimpleAccount(username, password, getName(), roleNames, null);
94          add(account);
95      }
96  
97      protected String getUsername(SimpleAccount account) {
98          return getUsername(account.getPrincipals());
99      }
100 
101     protected String getUsername(PrincipalCollection principals) {
102         return getAvailablePrincipal(principals).toString();
103     }
104 
105     protected void add(SimpleAccount account) {
106         String username = getUsername(account);
107         USERS_LOCK.writeLock().lock();
108         try {
109             this.users.put(username, account);
110         } finally {
111             USERS_LOCK.writeLock().unlock();
112         }
113     }
114 
115     protected SimpleRole getRole(String rolename) {
116         ROLES_LOCK.readLock().lock();
117         try {
118             return roles.get(rolename);
119         } finally {
120             ROLES_LOCK.readLock().unlock();
121         }
122     }
123 
124     public boolean roleExists(String name) {
125         return getRole(name) != null;
126     }
127 
128     public void addRole(String name) {
129         add(new SimpleRole(name));
130     }
131 
132     protected void add(SimpleRole role) {
133         ROLES_LOCK.writeLock().lock();
134         try {
135             roles.put(role.getName(), role);
136         } finally {
137             ROLES_LOCK.writeLock().unlock();
138         }
139     }
140 
141     protected static Set<String> toSet(String delimited, String delimiter) {
142         if (delimited == null || delimited.trim().equals("")) {
143             return null;
144         }
145 
146         Set<String> values = new HashSet<String>();
147         String[] rolenamesArray = delimited.split(delimiter);
148         for (String s : rolenamesArray) {
149             String trimmed = s.trim();
150             if (trimmed.length() > 0) {
151                 values.add(trimmed);
152             }
153         }
154 
155         return values;
156     }
157 
158     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
159         UsernamePasswordToken upToken = (UsernamePasswordToken) token;
160         SimpleAccount account = getUser(upToken.getUsername());
161 
162         if (account != null) {
163 
164             if (account.isLocked()) {
165                 throw new LockedAccountException("Account [" + account + "] is locked.");
166             }
167             if (account.isCredentialsExpired()) {
168                 String msg = "The credentials for account [" + account + "] are expired";
169                 throw new ExpiredCredentialsException(msg);
170             }
171 
172         }
173 
174         return account;
175     }
176 
177     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
178         String username = getUsername(principals);
179         USERS_LOCK.readLock().lock();
180         try {
181             return this.users.get(username);
182         } finally {
183             USERS_LOCK.readLock().unlock();
184         }
185     }
186 }