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.jndi;
20  
21  import java.util.ArrayList;
22  import java.util.Arrays;
23  import java.util.Collection;
24  import java.util.List;
25  
26  import org.apache.shiro.jndi.JndiLocator;
27  import org.apache.shiro.realm.Realm;
28  import org.apache.shiro.realm.RealmFactory;
29  import org.apache.shiro.util.StringUtils;
30  
31  
32  /**
33   * Looks up one or more Realm instances from JNDI using specified {@link #setJndiNames jndiNames}.
34   *
35   * <p>This is primarily provided to support Realm instances configured in JEE and EJB environments, but will
36   * work in any environment where {@link Realm Realm} instances are bound in JNDI instead of using
37   * programmatic or text-based configuration.
38   *
39   * @since 0.9
40   */
41  public class JndiRealmFactory extends JndiLocator implements RealmFactory {
42  
43      Collection<String> jndiNames = null;
44  
45      /**
46       * Returns the JNDI names that will be used to look up Realm(s) from JNDI.
47       *
48       * @return the JNDI names that will be used to look up Realm(s) from JNDI.
49       * @see #setJndiNames(String)
50       * @see #setJndiNames(Collection)
51       */
52      public Collection<String> getJndiNames() {
53          return jndiNames;
54      }
55  
56      /**
57       * Sets the JNDI names that will be used to look up Realm(s) from JNDI.
58       * <p/>
59       * The order of the collection determines the order that the Realms will be returned to the SecurityManager.
60       * <p/>
61       * If you find it easier to specify these names as a comma-delmited string, you may use the
62       * {@link #setJndiNames(String)} method instead.
63       *
64       * @param jndiNames the JNDI names that will be used to look up Realm(s) from JNDI.
65       * @see #setJndiNames(String)
66       */
67      public void setJndiNames(Collection<String> jndiNames) {
68          this.jndiNames = jndiNames;
69      }
70  
71      /**
72       * Specifies a comma-delimited list of JNDI names to lookup, each one corresponding to a jndi-bound
73       * {@link Realm Realm}.  The Realms will be made available to the SecurityManager in the order
74       * they are defined.
75       *
76       * @param commaDelimited a comma-delimited list of JNDI names, each representing the JNDI name used to
77       *                       look up a corresponding jndi-bound Realm.
78       * @throws IllegalStateException if the specified argument is null or the empty string.
79       */
80      public void setJndiNames(String commaDelimited) throws IllegalStateException {
81          String arg = StringUtils.clean(commaDelimited);
82          if (arg == null) {
83              String msg = "One or more comma-delimited jndi names must be specified for the " +
84                      getClass().getName() + " to locate Realms.";
85              throw new IllegalStateException(msg);
86          }
87          String[] names = StringUtils.tokenizeToStringArray(arg, ",");
88          setJndiNames(Arrays.asList(names));
89      }
90  
91      /**
92       * Performs the JNDI lookups for each specified {@link #getJndiNames() JNDI name} and returns all
93       * discovered Realms in an ordered collection.
94       *
95       * <p>The returned Collection is in the same order as the specified
96       * {@link #setJndiNames(java.util.Collection) jndiNames}
97       *
98       * @return an ordered collection of the {@link #setJndiNames(java.util.Collection) specified Realms} found in JNDI.
99       * @throws IllegalStateException if any of the JNDI names fails to successfully look up a Realm instance.
100      */
101     public Collection<Realm> getRealms() throws IllegalStateException {
102         Collection<String> jndiNames = getJndiNames();
103         if (jndiNames == null || jndiNames.isEmpty()) {
104             String msg = "One or more jndi names must be specified for the " +
105                     getClass().getName() + " to locate Realms.";
106             throw new IllegalStateException(msg);
107         }
108         List<Realm> realms = new ArrayList<Realm>(jndiNames.size());
109         for (String name : jndiNames) {
110             try {
111                 Realm realm = (Realm) lookup(name, Realm.class);
112                 realms.add(realm);
113             } catch (Exception e) {
114                 throw new IllegalStateException("Unable to look up realm with jndi name '" + name + "'.", e);
115             }
116         }
117         return realms.isEmpty() ? null : realms;
118     }
119 }