]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
dc948e6d73aa5b99b55724cdedd77d4615bc36ef
[tmp/jakarta-migration.git] /
1 /**
2  *  This document is a part of the source code and related artifacts
3  *  for CollectionSpace, an open source collections management system
4  *  for museums and related institutions:
5
6  *  http://www.collectionspace.org
7  *  http://wiki.collectionspace.org
8
9  *  Copyright 2009 University of California at Berkeley
10
11  *  Licensed under the Educational Community License (ECL), Version 2.0.
12  *  You may not use this file except in compliance with this License.
13
14  *  You may obtain a copy of the ECL 2.0 License at
15
16  *  https://source.collectionspace.org/collection-space/LICENSE.txt
17
18  *  Unless required by applicable law or agreed to in writing, software
19  *  distributed under the License is distributed on an "AS IS" BASIS,
20  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  *  See the License for the specific language governing permissions and
22  *  limitations under the License.
23  *//**
24  *  This document is a part of the source code and related artifacts
25  *  for CollectionSpace, an open source collections management system
26  *  for museums and related institutions:
27
28  *  http://www.collectionspace.org
29  *  http://wiki.collectionspace.org
30
31  *  Copyright 2009 University of California at Berkeley
32
33  *  Licensed under the Educational Community License (ECL), Version 2.0.
34  *  You may not use this file except in compliance with this License.
35
36  *  You may obtain a copy of the ECL 2.0 License at
37
38  *  https://source.collectionspace.org/collection-space/LICENSE.txt
39
40  *  Unless required by applicable law or agreed to in writing, software
41  *  distributed under the License is distributed on an "AS IS" BASIS,
42  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
43  *  See the License for the specific language governing permissions and
44  *  limitations under the License.
45  */
46 /*
47  * To change this template, choose Tools | Templates
48  * and open the template in the editor.
49  */
50 package org.collectionspace.authentication.realm;
51
52 import java.lang.reflect.Constructor;
53 import java.security.Principal;
54 import java.security.acl.Group;
55 import java.sql.Connection;
56 import java.sql.PreparedStatement;
57 import java.sql.ResultSet;
58 import java.sql.SQLException;
59 import java.util.Collection;
60 import java.util.HashMap;
61 import java.util.Map;
62 import javax.naming.InitialContext;
63 import javax.naming.NamingException;
64 import javax.security.auth.login.FailedLoginException;
65 import javax.security.auth.login.LoginException;
66 import javax.sql.DataSource;
67
68 import org.apache.commons.logging.Log;
69 import org.apache.commons.logging.LogFactory;
70 import org.collectionspace.authentication.CSpaceTenant;
71
72 /**
73  * CSpaceDbRealm provides access to user, password, role, tenant database
74  * @author 
75  */
76 public class CSpaceDbRealm implements CSpaceRealm {
77
78     private static Log log = LogFactory.getLog(CSpaceDbRealm.class);
79     private String datasourceName;
80     private String principalsQuery;
81     private String rolesQuery;
82     private String tenantsQuery;
83     private boolean suspendResume;
84
85     /**
86      * CSpace Database Realm
87      * @param datasourceName datasource name
88      */
89     public CSpaceDbRealm(Map options) {
90         datasourceName = (String) options.get("dsJndiName");
91         if (datasourceName == null) {
92             datasourceName = "java:/DefaultDS";
93         }
94         Object tmp = options.get("principalsQuery");
95         if (tmp != null) {
96             principalsQuery = tmp.toString();
97         }
98         tmp = options.get("rolesQuery");
99         if (tmp != null) {
100             rolesQuery = tmp.toString();
101         }
102         tmp = options.get("tenantsQuery");
103         if (tmp != null) {
104             tenantsQuery = tmp.toString();
105         }
106         tmp = options.get("suspendResume");
107         if (tmp != null) {
108             suspendResume = Boolean.valueOf(tmp.toString()).booleanValue();
109         }
110         if (log.isTraceEnabled()) {
111             log.trace("DatabaseServerLoginModule, dsJndiName=" + datasourceName);
112             log.trace("principalsQuery=" + principalsQuery);
113             log.trace("rolesQuery=" + rolesQuery);
114             log.trace("suspendResume=" + suspendResume);
115         }
116
117     }
118
119     @Override
120     public String getUsersPassword(String username) throws LoginException {
121
122         String password = null;
123         Connection conn = null;
124         PreparedStatement ps = null;
125         ResultSet rs = null;
126         try {
127             conn = getConnection();
128             // Get the password
129             if (log.isDebugEnabled()) {
130                 log.debug("Executing query: " + principalsQuery + ", with username: " + username);
131             }
132             ps = conn.prepareStatement(principalsQuery);
133             ps.setString(1, username);
134             rs = ps.executeQuery();
135             if (rs.next() == false) {
136                 if (log.isDebugEnabled()) {
137                     log.debug(principalsQuery + " returned no matches from db");
138                 }
139                 throw new FailedLoginException("No matching username found");
140             }
141
142             password = rs.getString(1);
143         } catch (SQLException ex) {
144             LoginException le = new LoginException("Query failed");
145             le.initCause(ex);
146             throw le;
147         } catch (Exception ex) {
148             LoginException le = new LoginException("Unknown Exception");
149             le.initCause(ex);
150             throw le;
151         } finally {
152             if (rs != null) {
153                 try {
154                     rs.close();
155                 } catch (SQLException e) {
156                 }
157             }
158             if (ps != null) {
159                 try {
160                     ps.close();
161                 } catch (SQLException e) {
162                 }
163             }
164             if (conn != null) {
165                 try {
166                     conn.close();
167                 } catch (SQLException ex) {
168                 }
169             }
170         }
171         return password;
172     }
173
174     /**
175      * Execute the rolesQuery against the datasourceName to obtain the roles for
176      * the authenticated user.
177      * @return collection containing the roles
178      */
179     @Override
180     public Collection<Group> getRoles(String username, String principalClassName, String groupClassName) throws LoginException {
181
182         if (log.isDebugEnabled()) {
183             log.debug("getRoleSets using rolesQuery: " + rolesQuery + ", username: " + username);
184         }
185
186         Connection conn = null;
187         HashMap<String, Group> groupsMap = new HashMap<String, Group>();
188         PreparedStatement ps = null;
189         ResultSet rs = null;
190
191         try {
192             conn = getConnection();
193             // Get the user role names
194             if (log.isDebugEnabled()) {
195                 log.debug("Executing query: " + rolesQuery + ", with username: " + username);
196             }
197
198             ps = conn.prepareStatement(rolesQuery);
199             try {
200                 ps.setString(1, username);
201             } catch (ArrayIndexOutOfBoundsException ignore) {
202                 // The query may not have any parameters so just try it
203             }
204             rs = ps.executeQuery();
205             if (rs.next() == false) {
206                 if (log.isDebugEnabled()) {
207                     log.debug("No roles found");
208                 }
209 //                if(aslm.getUnauthenticatedIdentity() == null){
210 //                    throw new FailedLoginException("No matching username found in Roles");
211 //                }
212                 /* We are running with an unauthenticatedIdentity so create an
213                 empty Roles set and return.
214                  */
215
216                 Group g = createGroup(groupClassName, "Roles");
217                 groupsMap.put(g.getName(), g);
218                 return groupsMap.values();
219             }
220
221             do {
222                 String roleName = rs.getString(1);
223                 String groupName = rs.getString(2);
224                 if (groupName == null || groupName.length() == 0) {
225                     groupName = "Roles";
226                 }
227
228                 Group group = (Group) groupsMap.get(groupName);
229                 if (group == null) {
230                     group = createGroup(groupClassName, groupName);
231                     groupsMap.put(groupName, group);
232                 }
233
234                 try {
235                     Principal p = createPrincipal(principalClassName, roleName);
236                     if (log.isDebugEnabled()) {
237                         log.debug("Assign user to role " + roleName);
238                     }
239
240                     group.addMember(p);
241                 } catch (Exception e) {
242                     log.error("Failed to create principal: " + roleName + " " + e.toString());
243                 }
244
245             } while (rs.next());
246         } catch (SQLException ex) {
247             LoginException le = new LoginException("Query failed");
248             le.initCause(ex);
249             throw le;
250         } catch (Exception e) {
251             LoginException le = new LoginException("unknown exception");
252             le.initCause(e);
253             throw le;
254         } finally {
255             if (rs != null) {
256                 try {
257                     rs.close();
258                 } catch (SQLException e) {
259                 }
260             }
261             if (ps != null) {
262                 try {
263                     ps.close();
264                 } catch (SQLException e) {
265                 }
266             }
267             if (conn != null) {
268                 try {
269                     conn.close();
270                 } catch (Exception ex) {
271                 }
272             }
273
274         }
275
276         return groupsMap.values();
277
278     }
279
280     /**
281      * Execute the tenantsQuery against the datasourceName to obtain the tenants for
282      * the authenticated user.
283      * @return collection containing the roles
284      */
285     @Override
286     public Collection<Group> getTenants(String username, String groupClassName) throws LoginException {
287
288         if (log.isDebugEnabled()) {
289             log.debug("getTenants using tenantsQuery: " + tenantsQuery + ", username: " + username);
290         }
291
292         Connection conn = null;
293         HashMap<String, Group> groupsMap = new HashMap<String, Group>();
294         PreparedStatement ps = null;
295         ResultSet rs = null;
296
297         try {
298             conn = getConnection();
299             // Get the user role names
300             if (log.isDebugEnabled()) {
301                 log.debug("Executing query: " + tenantsQuery + ", with username: " + username);
302             }
303
304             ps = conn.prepareStatement(tenantsQuery);
305             try {
306                 ps.setString(1, username);
307             } catch (ArrayIndexOutOfBoundsException ignore) {
308                 // The query may not have any parameters so just try it
309             }
310             rs = ps.executeQuery();
311             if (rs.next() == false) {
312                 if (log.isDebugEnabled()) {
313                     log.debug("No tenants found");
314                 }
315                 // We are running with an unauthenticatedIdentity so create an
316                 // empty Tenants set and return.
317                 // FIXME  should this be allowed?
318                 Group g = createGroup(groupClassName, "Tenants");
319                 groupsMap.put(g.getName(), g);
320                 return groupsMap.values();
321             }
322
323             do {
324                 String tenantId = rs.getString(1);
325                 String tenantName = rs.getString(2);
326                 String groupName = rs.getString(3);
327                 if (groupName == null || groupName.length() == 0) {
328                     groupName = "Tenants";
329                 }
330
331                 Group group = (Group) groupsMap.get(groupName);
332                 if (group == null) {
333                     group = createGroup(groupClassName, groupName);
334                     groupsMap.put(groupName, group);
335                 }
336
337                 try {
338                     Principal p = createTenant(tenantName, tenantId);
339                     if (log.isDebugEnabled()) {
340                         log.debug("Assign user to tenant " + tenantName);
341                     }
342
343                     group.addMember(p);
344                 } catch (Exception e) {
345                     log.error("Failed to create tenant: " + tenantName + " " + e.toString());
346                 }
347             } while (rs.next());
348         } catch (SQLException ex) {
349             LoginException le = new LoginException("Query failed");
350             le.initCause(ex);
351             throw le;
352         } catch (Exception e) {
353             LoginException le = new LoginException("unknown exception");
354             le.initCause(e);
355             throw le;
356         } finally {
357             if (rs != null) {
358                 try {
359                     rs.close();
360                 } catch (SQLException e) {
361                 }
362             }
363             if (ps != null) {
364                 try {
365                     ps.close();
366                 } catch (SQLException e) {
367                 }
368             }
369             if (conn != null) {
370                 try {
371                     conn.close();
372                 } catch (Exception ex) {
373                 }
374             }
375
376         }
377
378         return groupsMap.values();
379     }
380
381     private CSpaceTenant createTenant(String name, String id) throws Exception {
382         return new CSpaceTenant(name, id);
383     }
384
385     private Group createGroup(String groupClassName, String name) throws Exception {
386         return (Group) createPrincipal(groupClassName, name);
387     }
388
389     private Principal createPrincipal(String principalClassName, String name) throws Exception {
390         ClassLoader loader = Thread.currentThread().getContextClassLoader();
391         Class clazz = loader.loadClass(principalClassName);
392         Class[] ctorSig = {String.class};
393         Constructor ctor = clazz.getConstructor(ctorSig);
394         Object[] ctorArgs = {name};
395         Principal p = (Principal) ctor.newInstance(ctorArgs);
396         return p;
397     }
398
399     private Connection getConnection() throws LoginException, SQLException {
400         InitialContext ctx = null;
401         Connection conn = null;
402         try {
403             ctx = new InitialContext();
404             DataSource ds = (DataSource) ctx.lookup(getDataSourceName());
405             if (ds == null) {
406                 throw new IllegalArgumentException("datasource not found: " + getDataSourceName());
407             }
408             conn = ds.getConnection();
409             return conn;
410         } catch (NamingException ex) {
411             LoginException le = new LoginException("Error looking up DataSource from: " + getDataSourceName());
412             le.initCause(ex);
413             throw le;
414         } finally {
415             if (ctx != null) {
416                 try {
417                     ctx.close();
418                 } catch (Exception e) {
419                 }
420             }
421         }
422
423     }
424
425     /**
426      * @return the datasourceName
427      */
428     public String getDataSourceName() {
429         return datasourceName;
430     }
431
432     /**
433      * @return the principalQuery
434      */
435     public String getPrincipalQuery() {
436         return principalsQuery;
437     }
438
439     /**
440      * @param principalQuery the principalQuery to set
441      */
442     public void setPrincipalQuery(String principalQuery) {
443         this.principalsQuery = principalQuery;
444     }
445
446     /**
447      * @return the roleQuery
448      */
449     public String getRoleQuery() {
450         return rolesQuery;
451     }
452
453     /**
454      * @param roleQuery the roleQuery to set
455      */
456     public void setRoleQuery(String roleQuery) {
457         this.rolesQuery = roleQuery;
458     }
459
460     /**
461      * @return the tenantQuery
462      */
463     public String getTenantQuery() {
464         return tenantsQuery;
465     }
466
467     /**
468      * @param tenantQuery the tenantQuery to set
469      */
470     public void setTenantQuery(String tenantQuery) {
471         this.tenantsQuery = tenantQuery;
472     }
473 }