Java tutorial
/** * This document is a part of the source code and related artifacts * for CollectionSpace, an open source collections management system * for museums and related institutions: * http://www.collectionspace.org * http://wiki.collectionspace.org * Copyright 2009 University of California at Berkeley * Licensed under the Educational Community License (ECL), Version 2.0. * You may not use this file except in compliance with this License. * You may obtain a copy of the ECL 2.0 License at * https://source.collectionspace.org/collection-space/LICENSE.txt * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * This document is a part of the source code and related artifacts * for CollectionSpace, an open source collections management system * for museums and related institutions: * http://www.collectionspace.org * http://wiki.collectionspace.org * Copyright 2009 University of California at Berkeley * Licensed under the Educational Community License (ECL), Version 2.0. * You may not use this file except in compliance with this License. * You may obtain a copy of the ECL 2.0 License at * https://source.collectionspace.org/collection-space/LICENSE.txt * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.collectionspace.authentication.realm.db; import java.lang.reflect.Constructor; import java.security.Principal; import java.security.acl.Group; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collection; import java.util.HashMap; import java.util.Map; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.security.auth.login.FailedLoginException; import javax.security.auth.login.LoginException; import javax.sql.DataSource; //import org.apache.commons.logging.Log; //import org.apache.commons.logging.LogFactory; import org.collectionspace.authentication.CSpaceTenant; import org.collectionspace.authentication.realm.CSpaceRealm; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * CSpaceDbRealm provides access to user, password, role, tenant database * @author */ public class CSpaceDbRealm implements CSpaceRealm { private Logger logger = LoggerFactory.getLogger(CSpaceDbRealm.class); private String datasourceName; private String principalsQuery; private String rolesQuery; private String tenantsQuery; private boolean suspendResume; /** * CSpace Database Realm * @param datasourceName datasource name */ public CSpaceDbRealm(Map options) { datasourceName = (String) options.get("dsJndiName"); if (datasourceName == null) { datasourceName = "java:/DefaultDS"; } Object tmp = options.get("principalsQuery"); if (tmp != null) { principalsQuery = tmp.toString(); } tmp = options.get("rolesQuery"); if (tmp != null) { rolesQuery = tmp.toString(); } tmp = options.get("tenantsQuery"); if (tmp != null) { tenantsQuery = tmp.toString(); } tmp = options.get("suspendResume"); if (tmp != null) { suspendResume = Boolean.valueOf(tmp.toString()).booleanValue(); } if (logger.isTraceEnabled()) { logger.trace("DatabaseServerLoginModule, dsJndiName=" + datasourceName); logger.trace("principalsQuery=" + principalsQuery); logger.trace("rolesQuery=" + rolesQuery); logger.trace("suspendResume=" + suspendResume); } } @Override public String getUsersPassword(String username) throws LoginException { String password = null; Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = getConnection(); // Get the password if (logger.isDebugEnabled()) { logger.debug("Executing query: " + principalsQuery + ", with username: " + username); } ps = conn.prepareStatement(principalsQuery); ps.setString(1, username); rs = ps.executeQuery(); if (rs.next() == false) { if (logger.isDebugEnabled()) { logger.debug(principalsQuery + " returned no matches from db"); } throw new FailedLoginException("No matching username found"); } password = rs.getString(1); } catch (SQLException ex) { LoginException le = new LoginException("Query failed"); le.initCause(ex); throw le; } catch (Exception ex) { LoginException le = new LoginException("Unknown Exception"); le.initCause(ex); throw le; } finally { if (rs != null) { try { rs.close(); } catch (SQLException e) { } } if (ps != null) { try { ps.close(); } catch (SQLException e) { } } if (conn != null) { try { conn.close(); } catch (SQLException ex) { } } } return password; } /** * Execute the rolesQuery against the datasourceName to obtain the roles for * the authenticated user. * @return collection containing the roles */ @Override public Collection<Group> getRoles(String username, String principalClassName, String groupClassName) throws LoginException { if (logger.isDebugEnabled()) { logger.debug("getRoleSets using rolesQuery: " + rolesQuery + ", username: " + username); } Connection conn = null; HashMap<String, Group> groupsMap = new HashMap<String, Group>(); PreparedStatement ps = null; ResultSet rs = null; try { conn = getConnection(); // Get the user role names if (logger.isDebugEnabled()) { logger.debug("Executing query: " + rolesQuery + ", with username: " + username); } ps = conn.prepareStatement(rolesQuery); try { ps.setString(1, username); } catch (ArrayIndexOutOfBoundsException ignore) { // The query may not have any parameters so just try it } rs = ps.executeQuery(); if (rs.next() == false) { if (logger.isDebugEnabled()) { logger.debug("No roles found"); } // if(aslm.getUnauthenticatedIdentity() == null){ // throw new FailedLoginException("No matching username found in Roles"); // } /* We are running with an unauthenticatedIdentity so create an empty Roles set and return. */ Group g = createGroup(groupClassName, "Roles"); groupsMap.put(g.getName(), g); return groupsMap.values(); } do { String roleName = rs.getString(1); String groupName = rs.getString(2); if (groupName == null || groupName.length() == 0) { groupName = "Roles"; } Group group = (Group) groupsMap.get(groupName); if (group == null) { group = createGroup(groupClassName, groupName); groupsMap.put(groupName, group); } try { Principal p = createPrincipal(principalClassName, roleName); if (logger.isDebugEnabled()) { logger.debug("Assign user to role " + roleName); } group.addMember(p); } catch (Exception e) { logger.error("Failed to create principal: " + roleName + " " + e.toString()); } } while (rs.next()); } catch (SQLException ex) { LoginException le = new LoginException("Query failed"); le.initCause(ex); throw le; } catch (Exception e) { LoginException le = new LoginException("unknown exception"); le.initCause(e); throw le; } finally { if (rs != null) { try { rs.close(); } catch (SQLException e) { } } if (ps != null) { try { ps.close(); } catch (SQLException e) { } } if (conn != null) { try { conn.close(); } catch (Exception ex) { } } } return groupsMap.values(); } /** * Execute the tenantsQuery against the datasourceName to obtain the tenants for * the authenticated user. * @return collection containing the roles */ @Override public Collection<Group> getTenants(String username, String groupClassName) throws LoginException { if (logger.isDebugEnabled()) { logger.debug("getTenants using tenantsQuery: " + tenantsQuery + ", username: " + username); } Connection conn = null; HashMap<String, Group> groupsMap = new HashMap<String, Group>(); PreparedStatement ps = null; ResultSet rs = null; try { conn = getConnection(); // Get the user role names if (logger.isDebugEnabled()) { logger.debug("Executing query: " + tenantsQuery + ", with username: " + username); } ps = conn.prepareStatement(tenantsQuery); try { ps.setString(1, username); } catch (ArrayIndexOutOfBoundsException ignore) { // The query may not have any parameters so just try it } rs = ps.executeQuery(); if (rs.next() == false) { if (logger.isDebugEnabled()) { logger.debug("No tenants found"); } // We are running with an unauthenticatedIdentity so create an // empty Tenants set and return. // FIXME should this be allowed? Group g = createGroup(groupClassName, "Tenants"); groupsMap.put(g.getName(), g); return groupsMap.values(); } do { String tenantId = rs.getString(1); String tenantName = rs.getString(2); String groupName = rs.getString(3); if (groupName == null || groupName.length() == 0) { groupName = "Tenants"; } Group group = (Group) groupsMap.get(groupName); if (group == null) { group = createGroup(groupClassName, groupName); groupsMap.put(groupName, group); } try { Principal p = createTenant(tenantName, tenantId); if (logger.isDebugEnabled()) { logger.debug("Assign user to tenant " + tenantName); } group.addMember(p); } catch (Exception e) { logger.error("Failed to create tenant: " + tenantName + " " + e.toString()); } } while (rs.next()); } catch (SQLException ex) { LoginException le = new LoginException("Query failed"); le.initCause(ex); throw le; } catch (Exception e) { LoginException le = new LoginException("unknown exception"); le.initCause(e); throw le; } finally { if (rs != null) { try { rs.close(); } catch (SQLException e) { } } if (ps != null) { try { ps.close(); } catch (SQLException e) { } } if (conn != null) { try { conn.close(); } catch (Exception ex) { } } } return groupsMap.values(); } private CSpaceTenant createTenant(String name, String id) throws Exception { return new CSpaceTenant(name, id); } private Group createGroup(String groupClassName, String name) throws Exception { return (Group) createPrincipal(groupClassName, name); } private Principal createPrincipal(String principalClassName, String name) throws Exception { ClassLoader loader = Thread.currentThread().getContextClassLoader(); Class clazz = loader.loadClass(principalClassName); Class[] ctorSig = { String.class }; Constructor ctor = clazz.getConstructor(ctorSig); Object[] ctorArgs = { name }; Principal p = (Principal) ctor.newInstance(ctorArgs); return p; } private Connection getConnection() throws LoginException, SQLException { InitialContext ctx = null; Connection conn = null; try { ctx = new InitialContext(); DataSource ds = (DataSource) ctx.lookup(getDataSourceName()); if (ds == null) { throw new IllegalArgumentException("datasource not found: " + getDataSourceName()); } conn = ds.getConnection(); return conn; } catch (NamingException ex) { LoginException le = new LoginException("Error looking up DataSource from: " + getDataSourceName()); le.initCause(ex); throw le; } finally { if (ctx != null) { try { ctx.close(); } catch (Exception e) { } } } } /** * @return the datasourceName */ public String getDataSourceName() { return datasourceName; } /** * @return the principalQuery */ public String getPrincipalQuery() { return principalsQuery; } /** * @param principalQuery the principalQuery to set */ public void setPrincipalQuery(String principalQuery) { this.principalsQuery = principalQuery; } /** * @return the roleQuery */ public String getRoleQuery() { return rolesQuery; } /** * @param roleQuery the roleQuery to set */ public void setRoleQuery(String roleQuery) { this.rolesQuery = roleQuery; } /** * @return the tenantQuery */ public String getTenantQuery() { return tenantsQuery; } /** * @param tenantQuery the tenantQuery to set */ public void setTenantQuery(String tenantQuery) { this.tenantsQuery = tenantQuery; } }