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

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

/**
 * 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.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.sql.OCommandSQL; import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery; import com.orientechnologies.orient.server.OServer; import com.orientechnologies.orient.server.config.OServerConfigurationManager; import com.orientechnologies.orient.server.security.OSecurityAuthenticator; import com.orientechnologies.orient.server.security.OSecurityComponent; import javax.naming.directory.DirContext; import javax.security.auth.Subject; import java.util.*; import java.util.concurrent.ConcurrentHashMap; /** * 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 OServer _Server; 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(); // 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 = _Server.getSecurity().openDatabase(db.getName()); 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 OServer oServer, final OServerConfigurationManager serverCfg, final ODocument importDoc) { try { _Server = oServer; _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 authentication is null, it defaults to "GSSAPI" (Kerberos). String authentication = null; // We check this for backwards compatibility as we renamed the property to "authentication". if (dbDomainDoc.containsField("authenticator")) { authentication = dbDomainDoc.field("authenticator"); } if (dbDomainDoc.containsField("authentication")) { authentication = dbDomainDoc.field("authentication"); } 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"); String principal = ""; if (ldapServerDoc.containsField("principal")) principal = ldapServerDoc.field("principal"); String credentials = ""; if (ldapServerDoc.containsField("credentials")) credentials = ldapServerDoc.field("credentials"); OLDAPServer server = OLDAPServer.validateURL(url, isAlias, principal, credentials); 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, authentication); 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) { _Name = name; _IgnoreLocal = ignoreLocal; _DatabaseDomains = dbDomains; } } private class DatabaseDomain { private String _Domain; public String getDomain() { return _Domain; } private String _Authentication = "GSSAPI"; // Default to Kerberos private List _LDAPServers; private List _Users; public String getAuthentication() { return _Authentication; } public List getLDAPServers() { return _LDAPServers; } public List getUsers() { return _Users; } public DatabaseDomain(final String domain, final List ldapServers, final List userList, String authentication) { _Domain = domain; _LDAPServers = ldapServers; _Users = userList; _Authentication = authentication; } } 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) { _Roles.add(role); } } } public DatabaseUser(final String user) { _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) { _BaseDN = baseDN; _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 = _Server.getSecurity().getPrimaryAuthenticator(); else authMethod = _Server.getSecurity().getAuthenticator(authName); if (authMethod != null) subject = authMethod.getClientSubject(); return subject; } */ /*** * LDAP Import ***/ private synchronized void importLDAP() { if (_Server.getSecurity() == 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 = _Server.getSecurity().openDatabase(db.getName()); // 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); DirContext dc = OLDAPLibrary.openContext(_Server, dd.getAuthentication(), 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 = \"%s\"", OLDAPUserClass, domain); List users = new OSQLSynchQuery(sql).run(); for (ODocument userDoc : users) { String roles = userDoc.field("Roles"); if (roles != null) { List roleList = new ArrayList(); String[] roleArray = roles.split(","); for (String role : roleArray) { roleList.add(role.trim()); } User user = new User((String) userDoc.field("BaseDN"), (String) userDoc.field("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"; List users = new OSQLSynchQuery(sql).run(); for (ODocument user : users) { String name = user.field("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(new OCommandSQL("DELETE FROM OUser WHERE name = ?")).execute(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(new OCommandSQL(sb.toString())).execute(upn, password, roleParams, upn); db.command(new OCommandSQL(sb.toString())).execute(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