All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.orientechnologies.security.ldap.OLDAPImporter Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2010-2016 OrientDB LTD (http://orientdb.com)
 *
 * 

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * *

http://www.apache.org/licenses/LICENSE-2.0 * *

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. * *

For more information: http://www.orientdb.com */ package com.orientechnologies.security.ldap; import com.orientechnologies.common.log.OLogManager; import com.orientechnologies.orient.core.db.ODatabase; import com.orientechnologies.orient.core.db.OrientDBInternal; import com.orientechnologies.orient.core.metadata.schema.OClass; import com.orientechnologies.orient.core.metadata.schema.OProperty; import com.orientechnologies.orient.core.metadata.schema.OType; import com.orientechnologies.orient.core.record.impl.ODocument; import com.orientechnologies.orient.core.security.OSecurityAuthenticator; import com.orientechnologies.orient.core.security.OSecurityComponent; import com.orientechnologies.orient.core.security.OSecuritySystem; import com.orientechnologies.orient.core.sql.executor.OResult; import com.orientechnologies.orient.core.sql.executor.OResultSet; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import javax.naming.directory.DirContext; import javax.security.auth.Subject; /** * Provides an LDAP importer. * * @author S. Colin Leister */ public class OLDAPImporter implements OSecurityComponent { private final String oldapUserClass = "_OLDAPUser"; private boolean debug = false; private boolean enabled = true; private OrientDBInternal context; private int importPeriod = 60; // Default to 60 // seconds. private Timer importTimer; // Used to track what roles are assigned to each database user. // Holds a map of the import databases and their corresponding dbGroups. private final ConcurrentHashMap databaseMap = new ConcurrentHashMap(); private OSecuritySystem security; // OSecurityComponent public void active() { // Go through each database entry and check the _OLDAPUsers schema. for (Map.Entry dbEntry : databaseMap.entrySet()) { Database db = dbEntry.getValue(); ODatabase odb = null; try { odb = context.openNoAuthenticate(db.getName(), "internal"); verifySchema(odb); } catch (Exception ex) { OLogManager.instance().error(this, "OLDAPImporter.active() Database: %s", ex, db.getName()); } finally { if (odb != null) odb.close(); } } ImportTask importTask = new ImportTask(); importTimer = new Timer(true); importTimer.scheduleAtFixedRate( importTask, 30000, importPeriod * 1000); // Wait 30 seconds before starting OLogManager.instance().info(this, "**************************************"); OLogManager.instance().info(this, "** OrientDB LDAP Importer Is Active **"); OLogManager.instance().info(this, "**************************************"); } // OSecurityComponent public void config(final ODocument importDoc, OSecuritySystem security) { try { context = security.getContext(); this.security = security; databaseMap.clear(); if (importDoc.containsField("debug")) { debug = importDoc.field("debug"); } if (importDoc.containsField("enabled")) { enabled = importDoc.field("enabled"); } if (importDoc.containsField("period")) { importPeriod = importDoc.field("period"); if (debug) OLogManager.instance().info(this, "Import Period = " + importPeriod); } if (importDoc.containsField("databases")) { List list = importDoc.field("databases"); for (ODocument dbDoc : list) { if (dbDoc.containsField("database")) { String dbName = dbDoc.field("database"); if (debug) OLogManager.instance().info(this, "config() database: %s", dbName); boolean ignoreLocal = true; if (dbDoc.containsField("ignoreLocal")) { ignoreLocal = dbDoc.field("ignoreLocal"); } if (dbDoc.containsField("domains")) { final List dbDomainsList = new ArrayList(); final List dbdList = dbDoc.field("domains"); for (ODocument dbDomainDoc : dbdList) { String domain = null; // "domain" is mandatory. if (dbDomainDoc.containsField("domain")) { domain = dbDomainDoc.field("domain"); // If authenticator is null, it defaults to OLDAPImporter's primary // OSecurityAuthenticator. String authenticator = null; if (dbDomainDoc.containsField("authenticator")) { authenticator = dbDomainDoc.field("authenticator"); } if (dbDomainDoc.containsField("servers")) { final List ldapServerList = new ArrayList(); final List ldapServers = dbDomainDoc.field("servers"); for (ODocument ldapServerDoc : ldapServers) { final String url = ldapServerDoc.field("url"); boolean isAlias = false; if (ldapServerDoc.containsField("isAlias")) isAlias = ldapServerDoc.field("isAlias"); OLDAPServer server = OLDAPServer.validateURL(url, isAlias); if (server != null) { ldapServerList.add(server); } else { OLogManager.instance() .error( this, "Import LDAP Invalid server URL for database: %s, domain: %s, URL: %s", null, dbName, domain, url); } } // final List userList = new ArrayList(); final List userDocList = dbDomainDoc.field("users"); // userDocList can be null if only the oldapUserClass is used instead // security.json. if (userDocList != null) { for (ODocument userDoc : userDocList) { if (userDoc.containsField("baseDN") && userDoc.containsField("filter")) { if (userDoc.containsField("roles")) { final String baseDN = userDoc.field("baseDN"); final String filter = userDoc.field("filter"); if (debug) OLogManager.instance() .info( this, "config() database: %s, baseDN: %s, filter: %s", dbName, baseDN, filter); final List roleList = userDoc.field("roles"); final User User = new User(baseDN, filter, roleList); userList.add(User); } else { OLogManager.instance() .error( this, "Import LDAP The User's \"roles\" property is missing for database %s", null); } } else { OLogManager.instance() .error( this, "Import LDAP The User's \"baseDN\" or \"filter\" property is missing for database %s", null); } } } DatabaseDomain dbd = new DatabaseDomain(domain, ldapServerList, userList, authenticator); dbDomainsList.add(dbd); } else { OLogManager.instance() .error( this, "Import LDAP database %s \"domain\" is missing its \"servers\" property", null); } } else { OLogManager.instance() .error( this, "Import LDAP database %s \"domain\" object is missing its \"domain\" property", null); } } if (dbName != null) { Database db = new Database(dbName, ignoreLocal, dbDomainsList); databaseMap.put(dbName, db); } } else { OLogManager.instance() .error(this, "Import LDAP database %s contains no \"domains\" property", null); } } else { OLogManager.instance() .error(this, "Import LDAP databases contains no \"database\" property", null); } } } else { OLogManager.instance().error(this, "Import LDAP contains no \"databases\" property", null); } } catch (Exception ex) { OLogManager.instance().error(this, "OLDAPImporter.config()", ex); } } // OSecurityComponent public void dispose() { if (importTimer != null) { importTimer.cancel(); importTimer = null; } } // OSecurityComponent public boolean isEnabled() { return enabled; } private void verifySchema(ODatabase odb) { try { System.out.println("calling existsClass odb = " + odb); if (!odb.getMetadata().getSchema().existsClass(oldapUserClass)) { System.out.println("calling createClass"); OClass ldapUser = odb.getMetadata().getSchema().createClass(oldapUserClass); System.out.println("calling createProperty"); OProperty prop = ldapUser.createProperty("Domain", OType.STRING); System.out.println("calling setMandatory"); prop.setMandatory(true); prop.setNotNull(true); prop = ldapUser.createProperty("BaseDN", OType.STRING); prop.setMandatory(true); prop.setNotNull(true); prop = ldapUser.createProperty("Filter", OType.STRING); prop.setMandatory(true); prop.setNotNull(true); prop = ldapUser.createProperty("Roles", OType.STRING); prop.setMandatory(true); prop.setNotNull(true); } } catch (Exception ex) { OLogManager.instance().error(this, "OLDAPImporter.verifySchema()", ex); } } private class Database { private String name; public String getName() { return name; } private boolean ignoreLocal; public boolean ignoreLocal() { return ignoreLocal; } private List databaseDomains; public List getDatabaseDomains() { return databaseDomains; } public Database( final String name, final boolean ignoreLocal, final List dbDomains) { this.name = name; this.ignoreLocal = ignoreLocal; databaseDomains = dbDomains; } } private class DatabaseDomain { private String domain; public String getDomain() { return domain; } private String authenticator; private List ldapServers; private List users; public String getAuthenticator() { return authenticator; } public List getLDAPServers() { return ldapServers; } public List getUsers() { return users; } public DatabaseDomain( final String domain, final List ldapServers, final List userList, String authenticator) { this.domain = domain; this.ldapServers = ldapServers; users = userList; this.authenticator = authenticator; } } private class DatabaseUser { private String user; private Set roles = new LinkedHashSet(); private String getUser() { return user; } public Set getRoles() { return roles; } public void addRoles(Set roles) { if (roles != null) { for (String role : roles) { this.roles.add(role); } } } public DatabaseUser(final String user) { this.user = user; } } private class User { private String baseDN; private String filter; private Set roles = new LinkedHashSet(); public String getBaseDN() { return baseDN; } public String getFilter() { return filter; } public Set getRoles() { return roles; } public User(final String baseDN, final String filter, final List roleList) { this.baseDN = baseDN; this.filter = filter; // Convert the list into a set, for convenience. for (String role : roleList) { roles.add(role); } } } // OSecuritySystemAccess public Subject getLDAPSubject(final String authName) { Subject subject = null; OSecurityAuthenticator authMethod = null; // If authName is null, use the primary authentication method. if (authName == null) authMethod = security.getPrimaryAuthenticator(); else authMethod = security.getAuthenticator(authName); if (authMethod != null) subject = authMethod.getClientSubject(); return subject; } /** * LDAP Import * */ private synchronized void importLDAP() { if (security == null) { OLogManager.instance().error(this, "OLDAPImporter.importLDAP() ServerSecurity is null", null); return; } if (debug) OLogManager.instance().info(this, "OLDAPImporter.importLDAP() \n"); for (Map.Entry dbEntry : databaseMap.entrySet()) { try { Database db = dbEntry.getValue(); ODatabase odb = context.openNoAuthenticate(db.getName(), "internal"); // This set will be filled with all users from the database (unless ignoreLocal is true). // As each usersRetrieved list is filled, any matching user will be removed. // Once all the DatabaseGroups have been procesed, any remaining users in the set will be // deleted from the Database. Set usersToBeDeleted = new LinkedHashSet(); Map usersMap = new ConcurrentHashMap(); try { // We use this flag to determine whether to proceed with the call to deleteUsers() below. // If one or more LDAP servers cannot be reached (perhaps temporarily), we don't want to // delete all the database users, locking everyone out until the LDAP server is available // again. boolean deleteUsers = false; // Retrieves all the current OrientDB users from the specified ODatabase and stores them // in usersToBeDeleted. retrieveAllUsers(odb, db.ignoreLocal(), usersToBeDeleted); for (DatabaseDomain dd : db.getDatabaseDomains()) { try { Subject ldapSubject = getLDAPSubject(dd.getAuthenticator()); if (ldapSubject != null) { DirContext dc = OLDAPLibrary.openContext(ldapSubject, dd.getLDAPServers(), debug); if (dc != null) { deleteUsers = true; try { // Combine the "users" from security.json's "ldapImporter" and the class // oldapUserClass. List userList = new ArrayList(); userList.addAll(dd.getUsers()); retrieveLDAPUsers(odb, dd.getDomain(), userList); for (User user : userList) { List usersRetrieved = new ArrayList(); OLogManager.instance() .info( this, "OLDAPImporter.importLDAP() Calling retrieveUsers for Database: %s, Filter: %s", db.getName(), user.getFilter()); OLDAPLibrary.retrieveUsers( dc, user.getBaseDN(), user.getFilter(), usersRetrieved, debug); if (!usersRetrieved.isEmpty()) { for (String upn : usersRetrieved) { if (usersToBeDeleted.contains(upn)) usersToBeDeleted.remove(upn); OLogManager.instance() .info( this, "OLDAPImporter.importLDAP() Database: %s, Filter: %s, UPN: %s", db.getName(), user.getFilter(), upn); DatabaseUser dbUser = null; if (usersMap.containsKey(upn)) dbUser = usersMap.get(upn); else { dbUser = new DatabaseUser(upn); usersMap.put(upn, dbUser); } if (dbUser != null) { dbUser.addRoles(user.getRoles()); } } } else { OLogManager.instance() .info( this, "OLDAPImporter.importLDAP() No users found at BaseDN: %s, Filter: %s, for Database: %s", user.getBaseDN(), user.getFilter(), db.getName()); } } } finally { dc.close(); } } else { OLogManager.instance() .error( this, "OLDAPImporter.importLDAP() Could not obtain an LDAP DirContext for Database %s", null, db.getName()); } } else { OLogManager.instance() .error( this, "OLDAPImporter.importLDAP() Could not obtain an LDAP Subject for Database %s", null, db.getName()); } } catch (Exception ex) { OLogManager.instance() .error(this, "OLDAPImporter.importLDAP() Database: %s", ex, db.getName()); } } // Imports the LDAP users into the specified database, if it exists. importUsers(odb, usersMap); if (deleteUsers) deleteUsers(odb, usersToBeDeleted); } finally { if (usersMap != null) usersMap.clear(); if (usersToBeDeleted != null) usersToBeDeleted.clear(); if (odb != null) odb.close(); } } catch (Exception ex) { OLogManager.instance().error(this, "OLDAPImporter.importLDAP()", ex); } } } // Loads the User object from the oldapUserClass class for each domain. // This is equivalent to the "users" objects in "ldapImporter" of security.json. private void retrieveLDAPUsers( final ODatabase odb, final String domain, final List userList) { try { String sql = String.format("SELECT FROM `%s` WHERE Domain = ?", oldapUserClass); OResultSet users = odb.query(sql, domain); while (users.hasNext()) { OResult userDoc = users.next(); String roles = userDoc.getProperty("Roles"); if (roles != null) { List roleList = new ArrayList(); String[] roleArray = roles.split(","); for (String role : roleArray) { roleList.add(role.trim()); } User user = new User(userDoc.getProperty("BaseDN"), userDoc.getProperty("Filter"), roleList); userList.add(user); } else { OLogManager.instance() .error( this, "OLDAPImporter.retrieveLDAPUsers() Roles is missing for entry Database: %s, Domain: %s", null, odb.getName(), domain); } } } catch (Exception ex) { OLogManager.instance() .error( this, "OLDAPImporter.retrieveLDAPUsers() Database: %s, Domain: %s", ex, odb.getName(), domain); } } private void retrieveAllUsers( final ODatabase odb, final boolean ignoreLocal, final Set usersToBeDeleted) { try { String sql = "SELECT FROM OUser"; if (ignoreLocal) sql = "SELECT FROM OUser WHERE _externalUser = true"; OResultSet users = odb.query(sql); while (users.hasNext()) { OResult user = users.next(); String name = user.getProperty("name"); if (name != null) { if (!(name.equals("admin") || name.equals("reader") || name.equals("writer"))) { usersToBeDeleted.add(name); OLogManager.instance() .info( this, "OLDAPImporter.retrieveAllUsers() Database: %s, User: %s", odb.getName(), name); } } } } catch (Exception ex) { OLogManager.instance() .error(this, "OLDAPImporter.retrieveAllUsers() Database: %s", ex, odb.getName()); } } private void deleteUsers(final ODatabase odb, final Set usersToBeDeleted) { try { for (String user : usersToBeDeleted) { odb.command("DELETE FROM OUser WHERE name = ?", user); OLogManager.instance() .info( this, "OLDAPImporter.deleteUsers() Deleted User: %s from Database: %s", user, odb.getName()); } } catch (Exception ex) { OLogManager.instance() .error(this, "OLDAPImporter.deleteUsers() Database: %s", ex, odb.getName()); } } private void importUsers(final ODatabase odb, final Map usersMap) { try { for (Map.Entry entry : usersMap.entrySet()) { String upn = entry.getKey(); if (upsertDbUser(odb, upn, entry.getValue().getRoles())) OLogManager.instance() .info(this, "Added/Modified Database User %s in Database %s", upn, odb.getName()); else OLogManager.instance() .error( this, "Failed to add/update Database User %s in Database %s", null, upn, odb.getName()); } } catch (Exception ex) { OLogManager.instance() .error(this, "OLDAPImporter.importUsers() Database: %s", ex, odb.getName()); } } /* * private boolean dbUserExists(ODatabase db, String upn) { try { List list = new OSQLSynchQuery( * "SELECT FROM OUser WHERE name = ?").run(upn); * * return !list.isEmpty(); } catch(Exception ex) { OLogManager.instance().debug(this, "dbUserExists() Exception: ", ex); } * * return true; // Better to not add a user than to overwrite one. } */ private boolean upsertDbUser(ODatabase db, String upn, Set roles) { try { // Create a random password to set for each imported user in case allowDefault is set to true. // We don't want blank or simple passwords set on the imported users, just in case. // final String password = OSecurityManager.instance().createSHA256(String.valueOf(new // java.util.Random().nextLong())); final String password = UUID.randomUUID().toString(); StringBuilder sb = new StringBuilder(); sb.append( "UPDATE OUser SET name = ?, password = ?, status = \"ACTIVE\", _externalUser = true, roles = (SELECT FROM ORole WHERE name in ["); String[] roleParams = new String[roles.size()]; Iterator it = roles.iterator(); int cnt = 0; while (it.hasNext()) { String role = it.next(); sb.append("'"); sb.append(role); sb.append("'"); if (it.hasNext()) sb.append(", "); roleParams[cnt] = role; cnt++; } sb.append("]) UPSERT WHERE name = ?"); db.command(sb.toString(), upn, password, upn); return true; } catch (Exception ex) { OLogManager.instance().error(this, "OLDAPImporter.upsertDbUser()", ex); } return false; } private class ImportTask extends TimerTask { @Override public void run() { importLDAP(); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy