]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
fe3955cb7bf6c0478a82e881d90aa1ea28abbd93
[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.db;
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
71 import org.collectionspace.authentication.CSpaceTenant;
72 import org.collectionspace.authentication.realm.CSpaceRealm;
73
74 import org.slf4j.Logger;
75 import org.slf4j.LoggerFactory;
76
77 /**
78  * CSpaceDbRealm provides access to user, password, role, tenant database
79  * @author 
80  */
81 public class CSpaceDbRealm implements CSpaceRealm {
82
83     private Logger logger = LoggerFactory.getLogger(CSpaceDbRealm.class);
84     
85     private String datasourceName;
86     private String principalsQuery;
87     private String rolesQuery;
88     private String tenantsQuery;
89     private boolean suspendResume;
90
91     /**
92      * CSpace Database Realm
93      * @param datasourceName datasource name
94      */
95     public CSpaceDbRealm(Map options) {
96         datasourceName = (String) options.get("dsJndiName");
97         if (datasourceName == null) {
98             datasourceName = "java:/DefaultDS";
99         }
100         Object tmp = options.get("principalsQuery");
101         if (tmp != null) {
102             principalsQuery = tmp.toString();
103         }
104         tmp = options.get("rolesQuery");
105         if (tmp != null) {
106             rolesQuery = tmp.toString();
107         }
108         tmp = options.get("tenantsQuery");
109         if (tmp != null) {
110             tenantsQuery = tmp.toString();
111         }
112         tmp = options.get("suspendResume");
113         if (tmp != null) {
114             suspendResume = Boolean.valueOf(tmp.toString()).booleanValue();
115         }
116         if (logger.isTraceEnabled()) {
117             logger.trace("DatabaseServerLoginModule, dsJndiName=" + datasourceName);
118             logger.trace("principalsQuery=" + principalsQuery);
119             logger.trace("rolesQuery=" + rolesQuery);
120             logger.trace("suspendResume=" + suspendResume);
121         }
122
123     }
124
125     @Override
126     public String getUsersPassword(String username) throws LoginException {
127
128         String password = null;
129         Connection conn = null;
130         PreparedStatement ps = null;
131         ResultSet rs = null;
132         try {
133             conn = getConnection();
134             // Get the password
135             if (logger.isDebugEnabled()) {
136                 logger.debug("Executing query: " + principalsQuery + ", with username: " + username);
137             }
138             ps = conn.prepareStatement(principalsQuery);
139             ps.setString(1, username);
140             rs = ps.executeQuery();
141             if (rs.next() == false) {
142                 if (logger.isDebugEnabled()) {
143                     logger.debug(principalsQuery + " returned no matches from db");
144                 }
145                 throw new FailedLoginException("No matching username found");
146             }
147
148             password = rs.getString(1);
149         } catch (SQLException ex) {
150             LoginException le = new LoginException("Query failed");
151             le.initCause(ex);
152             throw le;
153         } catch (Exception ex) {
154             LoginException le = new LoginException("Unknown Exception");
155             le.initCause(ex);
156             throw le;
157         } finally {
158             if (rs != null) {
159                 try {
160                     rs.close();
161                 } catch (SQLException e) {
162                 }
163             }
164             if (ps != null) {
165                 try {
166                     ps.close();
167                 } catch (SQLException e) {
168                 }
169             }
170             if (conn != null) {
171                 try {
172                     conn.close();
173                 } catch (SQLException ex) {
174                 }
175             }
176         }
177         return password;
178     }
179
180     /**
181      * Execute the rolesQuery against the datasourceName to obtain the roles for
182      * the authenticated user.
183      * @return collection containing the roles
184      */
185     @Override
186     public Collection<Group> getRoles(String username, String principalClassName, String groupClassName) throws LoginException {
187
188         if (logger.isDebugEnabled()) {
189             logger.debug("getRoleSets using rolesQuery: " + rolesQuery + ", username: " + username);
190         }
191
192         Connection conn = null;
193         HashMap<String, Group> groupsMap = new HashMap<String, Group>();
194         PreparedStatement ps = null;
195         ResultSet rs = null;
196
197         try {
198             conn = getConnection();
199             // Get the user role names
200             if (logger.isDebugEnabled()) {
201                 logger.debug("Executing query: " + rolesQuery + ", with username: " + username);
202             }
203
204             ps = conn.prepareStatement(rolesQuery);
205             try {
206                 ps.setString(1, username);
207             } catch (ArrayIndexOutOfBoundsException ignore) {
208                 // The query may not have any parameters so just try it
209             }
210             rs = ps.executeQuery();
211             if (rs.next() == false) {
212                 if (logger.isDebugEnabled()) {
213                     logger.debug("No roles found");
214                 }
215 //                if(aslm.getUnauthenticatedIdentity() == null){
216 //                    throw new FailedLoginException("No matching username found in Roles");
217 //                }
218                 /* We are running with an unauthenticatedIdentity so create an
219                 empty Roles set and return.
220                  */
221
222                 Group g = createGroup(groupClassName, "Roles");
223                 groupsMap.put(g.getName(), g);
224                 return groupsMap.values();
225             }
226
227             do {
228                 String roleName = rs.getString(1);
229                 String groupName = rs.getString(2);
230                 if (groupName == null || groupName.length() == 0) {
231                     groupName = "Roles";
232                 }
233
234                 Group group = (Group) groupsMap.get(groupName);
235                 if (group == null) {
236                     group = createGroup(groupClassName, groupName);
237                     groupsMap.put(groupName, group);
238                 }
239
240                 try {
241                     Principal p = createPrincipal(principalClassName, roleName);
242                     if (logger.isDebugEnabled()) {
243                         logger.debug("Assign user to role " + roleName);
244                     }
245
246                     group.addMember(p);
247                 } catch (Exception e) {
248                     logger.error("Failed to create principal: " + roleName + " " + e.toString());
249                 }
250
251             } while (rs.next());
252         } catch (SQLException ex) {
253             LoginException le = new LoginException("Query failed");
254             le.initCause(ex);
255             throw le;
256         } catch (Exception e) {
257             LoginException le = new LoginException("unknown exception");
258             le.initCause(e);
259             throw le;
260         } finally {
261             if (rs != null) {
262                 try {
263                     rs.close();
264                 } catch (SQLException e) {
265                 }
266             }
267             if (ps != null) {
268                 try {
269                     ps.close();
270                 } catch (SQLException e) {
271                 }
272             }
273             if (conn != null) {
274                 try {
275                     conn.close();
276                 } catch (Exception ex) {
277                 }
278             }
279
280         }
281
282         return groupsMap.values();
283
284     }
285
286     /**
287      * Execute the tenantsQuery against the datasourceName to obtain the tenants for
288      * the authenticated user.
289      * @return collection containing the roles
290      */
291     @Override
292     public Collection<Group> getTenants(String username, String groupClassName) throws LoginException {
293
294         if (logger.isDebugEnabled()) {
295             logger.debug("getTenants using tenantsQuery: " + tenantsQuery + ", username: " + username);
296         }
297
298         Connection conn = null;
299         HashMap<String, Group> groupsMap = new HashMap<String, Group>();
300         PreparedStatement ps = null;
301         ResultSet rs = null;
302
303         try {
304             conn = getConnection();
305             // Get the user role names
306             if (logger.isDebugEnabled()) {
307                 logger.debug("Executing query: " + tenantsQuery + ", with username: " + username);
308             }
309
310             ps = conn.prepareStatement(tenantsQuery);
311             try {
312                 ps.setString(1, username);
313             } catch (ArrayIndexOutOfBoundsException ignore) {
314                 // The query may not have any parameters so just try it
315             }
316             rs = ps.executeQuery();
317             if (rs.next() == false) {
318                 if (logger.isDebugEnabled()) {
319                     logger.debug("No tenants found");
320                 }
321                 // We are running with an unauthenticatedIdentity so create an
322                 // empty Tenants set and return.
323                 // FIXME  should this be allowed?
324                 Group g = createGroup(groupClassName, "Tenants");
325                 groupsMap.put(g.getName(), g);
326                 return groupsMap.values();
327             }
328
329             do {
330                 String tenantId = rs.getString(1);
331                 String tenantName = rs.getString(2);
332                 String groupName = rs.getString(3);
333                 if (groupName == null || groupName.length() == 0) {
334                     groupName = "Tenants";
335                 }
336
337                 Group group = (Group) groupsMap.get(groupName);
338                 if (group == null) {
339                     group = createGroup(groupClassName, groupName);
340                     groupsMap.put(groupName, group);
341                 }
342
343                 try {
344                     Principal p = createTenant(tenantName, tenantId);
345                     if (logger.isDebugEnabled()) {
346                         logger.debug("Assign user to tenant " + tenantName);
347                     }
348
349                     group.addMember(p);
350                 } catch (Exception e) {
351                     logger.error("Failed to create tenant: " + tenantName + " " + e.toString());
352                 }
353             } while (rs.next());
354         } catch (SQLException ex) {
355             LoginException le = new LoginException("Query failed");
356             le.initCause(ex);
357             throw le;
358         } catch (Exception e) {
359             LoginException le = new LoginException("unknown exception");
360             le.initCause(e);
361             throw le;
362         } finally {
363             if (rs != null) {
364                 try {
365                     rs.close();
366                 } catch (SQLException e) {
367                 }
368             }
369             if (ps != null) {
370                 try {
371                     ps.close();
372                 } catch (SQLException e) {
373                 }
374             }
375             if (conn != null) {
376                 try {
377                     conn.close();
378                 } catch (Exception ex) {
379                 }
380             }
381
382         }
383
384         return groupsMap.values();
385     }
386
387     private CSpaceTenant createTenant(String name, String id) throws Exception {
388         return new CSpaceTenant(name, id);
389     }
390
391     private Group createGroup(String groupClassName, String name) throws Exception {
392         return (Group) createPrincipal(groupClassName, name);
393     }
394
395     private Principal createPrincipal(String principalClassName, String name) throws Exception {
396         ClassLoader loader = Thread.currentThread().getContextClassLoader();
397         Class clazz = loader.loadClass(principalClassName);
398         Class[] ctorSig = {String.class};
399         Constructor ctor = clazz.getConstructor(ctorSig);
400         Object[] ctorArgs = {name};
401         Principal p = (Principal) ctor.newInstance(ctorArgs);
402         return p;
403     }
404
405     private Connection getConnection() throws LoginException, SQLException {
406         InitialContext ctx = null;
407         Connection conn = null;
408         try {
409             ctx = new InitialContext();
410             DataSource ds = (DataSource) ctx.lookup(getDataSourceName());
411             if (ds == null) {
412                 throw new IllegalArgumentException("datasource not found: " + getDataSourceName());
413             }
414             conn = ds.getConnection();
415             return conn;
416         } catch (NamingException ex) {
417             LoginException le = new LoginException("Error looking up DataSource from: " + getDataSourceName());
418             le.initCause(ex);
419             throw le;
420         } finally {
421             if (ctx != null) {
422                 try {
423                     ctx.close();
424                 } catch (Exception e) {
425                 }
426             }
427         }
428
429     }
430
431     /**
432      * @return the datasourceName
433      */
434     public String getDataSourceName() {
435         return datasourceName;
436     }
437
438     /**
439      * @return the principalQuery
440      */
441     public String getPrincipalQuery() {
442         return principalsQuery;
443     }
444
445     /**
446      * @param principalQuery the principalQuery to set
447      */
448     public void setPrincipalQuery(String principalQuery) {
449         this.principalsQuery = principalQuery;
450     }
451
452     /**
453      * @return the roleQuery
454      */
455     public String getRoleQuery() {
456         return rolesQuery;
457     }
458
459     /**
460      * @param roleQuery the roleQuery to set
461      */
462     public void setRoleQuery(String roleQuery) {
463         this.rolesQuery = roleQuery;
464     }
465
466     /**
467      * @return the tenantQuery
468      */
469     public String getTenantQuery() {
470         return tenantsQuery;
471     }
472
473     /**
474      * @param tenantQuery the tenantQuery to set
475      */
476     public void setTenantQuery(String tenantQuery) {
477         this.tenantsQuery = tenantQuery;
478     }
479 }