{"action":"created","comment":{"url":"https://api.github.com/repos/codice/ddf/pulls/comments/59946797","id":59946797,"diff_hunk":"@@ -0,0 +1,116 @@\n+/**\n+ * Copyright (c) Codice Foundation\n+ * <p>\n+ * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser\n+ * General Public License as published by the Free Software Foundation, either version 3 of the\n+ * License, or any later version.\n+ * <p>\n+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without\n+ * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details. A copy of the GNU Lesser General Public License\n+ * is distributed along with this program and can be found at\n+ * <http://www.gnu.org/licenses/lgpl.html>.\n+ */\n+package ddf.ldap.ldaplogin;\n+\n+import java.util.ArrayList;\n+import java.util.List;\n+\n+import org.apache.karaf.jaas.config.JaasRealm;\n+import org.apache.karaf.jaas.config.impl.Config;\n+import org.apache.karaf.jaas.config.impl.Module;\n+import org.osgi.framework.Bundle;\n+import org.osgi.framework.BundleContext;\n+import org.osgi.framework.FrameworkUtil;\n+import org.slf4j.Logger;\n+import org.slf4j.LoggerFactory;\n+\n+public class LdapService {\n+\n+    private static final Logger LOGGER = LoggerFactory.getLogger(LdapService.class);\n+\n+    private static final String CONFIG_NAME = \"ldap\";\n+\n+    private Config config;\n+\n+    private BundleContext context;\n+\n+    private List<Module> modules;\n+\n+    public LdapService() {\n+        config = new Config();\n+        modules = new ArrayList<>();\n+        context = getContext();\n+        config.setBundleContext(context);\n+        config.setName(CONFIG_NAME);\n+        config.setRank(2);\n+        config.setModules(new Module[] {});\n+\n+        LOGGER.debug(\"Registering new service as a JaasRealm.\");\n+        context.registerService(JaasRealm.class, config, null);\n+    }\n+\n+    /**\n+     * Updates an existing ldap module with a new one or adds a\n+     * new module to the list of existing modules.\n+     *\n+     * @param newModule that will replace a module or be added to the list of modules.\n+     */\n+    public synchronized void update(Module newModule) {\n+        boolean isExistingModule = false;\n+        if (modules.isEmpty()) {\n+            modules.add(newModule);\n+        } else {\n+            for (int i = 0; i < modules.size(); i++) {\n+                if (modules.get(i)\n+                        .getName()\n+                        .equals(newModule.getName())) {\n+                    modules.set(i, newModule);\n+                    isExistingModule = true;\n+                    break;\n+                }\n+            }\n+            if (!isExistingModule) {\n+                modules.add(newModule);\n+            }\n+        }\n+        config.setModules(modules.toArray(new Module[modules.size()]));\n+    }\n+\n+    /**\n+     * Delete an ldap module given its id.\n+     *\n+     * @param id of the module.\n+     * @return true, if the delete was successful, false otherwise.\n+     */\n+    public synchronized boolean delete(String id) {\n+        boolean isModuleDeleted = false;\n+        for (int i = 0; i < modules.size(); i++) {","path":"platform/security/sts/security-sts-ldaplogin/src/main/java/ddf/ldap/ldaplogin/LdapService.java","position":88,"original_position":88,"commit_id":"2141ed3ffd826deb300a29218847666036199b39","original_commit_id":"2141ed3ffd826deb300a29218847666036199b39","user":{"login":"roelens8","id":5935039,"avatar_url":"https://avatars.githubusercontent.com/u/5935039?v=3","gravatar_id":"","url":"https://api.github.com/users/roelens8","html_url":"https://github.com/roelens8","followers_url":"https://api.github.com/users/roelens8/followers","following_url":"https://api.github.com/users/roelens8/following{/other_user}","gists_url":"https://api.github.com/users/roelens8/gists{/gist_id}","starred_url":"https://api.github.com/users/roelens8/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/roelens8/subscriptions","organizations_url":"https://api.github.com/users/roelens8/orgs","repos_url":"https://api.github.com/users/roelens8/repos","events_url":"https://api.github.com/users/roelens8/events{/privacy}","received_events_url":"https://api.github.com/users/roelens8/received_events","type":"User","site_admin":false},"body":"👍 ","created_at":"2016-04-15T21:55:56Z","updated_at":"2016-04-15T21:55:56Z","html_url":"https://github.com/codice/ddf/pull/706#discussion_r59946797","pull_request_url":"https://api.github.com/repos/codice/ddf/pulls/706","_links":{"self":{"href":"https://api.github.com/repos/codice/ddf/pulls/comments/59946797"},"html":{"href":"https://github.com/codice/ddf/pull/706#discussion_r59946797"},"pull_request":{"href":"https://api.github.com/repos/codice/ddf/pulls/706"}}},"pull_request":{"url":"https://api.github.com/repos/codice/ddf/pulls/706","id":66704084,"html_url":"https://github.com/codice/ddf/pull/706","diff_url":"https://github.com/codice/ddf/pull/706.diff","patch_url":"https://github.com/codice/ddf/pull/706.patch","issue_url":"https://api.github.com/repos/codice/ddf/issues/706","number":706,"state":"open","locked":false,"title":"DDF-2033 Add support for connecting to multiple LDAP servers at the s…","user":{"login":"roelens8","id":5935039,"avatar_url":"https://avatars.githubusercontent.com/u/5935039?v=3","gravatar_id":"","url":"https://api.github.com/users/roelens8","html_url":"https://github.com/roelens8","followers_url":"https://api.github.com/users/roelens8/followers","following_url":"https://api.github.com/users/roelens8/following{/other_user}","gists_url":"https://api.github.com/users/roelens8/gists{/gist_id}","starred_url":"https://api.github.com/users/roelens8/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/roelens8/subscriptions","organizations_url":"https://api.github.com/users/roelens8/orgs","repos_url":"https://api.github.com/users/roelens8/repos","events_url":"https://api.github.com/users/roelens8/events{/privacy}","received_events_url":"https://api.github.com/users/roelens8/received_events","type":"User","site_admin":false},"body":"#### What does this PR do?\r\nAdds support for connecting to multiple LDAP servers at the same time so that users from different LDAPs can login to DDF.\r\n#### Who is reviewing it (please choose AT LEAST two reviewers that need to approve the PR before it can get merged; if a component team is listed, at least one of its members needs to approve)?\r\n@ryeats @tbatie @jckilmer @bcwaters @coyotesqrl @kcwire \r\n#### Choose 2 committers to review/merge the PR (please choose ONLY two committers from below, delete the rest)\r\n@pklinef \r\n@stustison\r\n#### How should this be tested?\r\nIn order to fully test this PR, connecting at least two LDAP Servers to a single DDF is required.\r\n\r\nInstructions for connecting to LDAP server(s):\r\n1. Install 'OpenDj Embedded'\r\n2. Configure 'LDAP Server' with desired port numbers\r\n3. Install 'security-sts-ldaplogin' and 'security-sts-ldapclaimshandler'\r\n4. Configure 'Security STS LDAP Login' and 'Security STS LDAP and Roles Claims Handler' with the LDAP information of the LDAP you want to connect to. Connecting to multiple LDAPs will require creating a new set of these configurations.  (Note: the SSL Keystore Alias needs to be set to your own server's keystore alias even when connecting to an LDAP located on another server).\r\n5. Configure the Web Context Policy\r\n    Add the following to the Context Realms: '/search=ldap'', /services=ldap', '/cometd=ldap'\r\n6. Login the Search UI with a different user from each connected LDAP. (Note: Make sure the user you login as does not exist in any other LDAPs.)\r\n\r\n#### Any background context you want to provide?\r\n#### What are the relevant tickets?\r\nDDF-2033\r\n#### Screenshots (if appropriate)\r\n#### Checklist:\r\n- [ ] Documentation Updated\r\n- [X] Update / Add Unit Tests\r\n- [ ] Update / Add Integration Tests\r\n\r\n…ame time","created_at":"2016-04-15T20:59:31Z","updated_at":"2016-04-15T21:55:56Z","closed_at":null,"merged_at":null,"merge_commit_sha":"f34a629b75d8b1cac98f54913f418fefc875c9ba","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/codice/ddf/pulls/706/commits","review_comments_url":"https://api.github.com/repos/codice/ddf/pulls/706/comments","review_comment_url":"https://api.github.com/repos/codice/ddf/pulls/comments{/number}","comments_url":"https://api.github.com/repos/codice/ddf/issues/706/comments","statuses_url":"https://api.github.com/repos/codice/ddf/statuses/2141ed3ffd826deb300a29218847666036199b39","head":{"label":"roelens8:DDF-2033","ref":"DDF-2033","sha":"2141ed3ffd826deb300a29218847666036199b39","user":{"login":"roelens8","id":5935039,"avatar_url":"https://avatars.githubusercontent.com/u/5935039?v=3","gravatar_id":"","url":"https://api.github.com/users/roelens8","html_url":"https://github.com/roelens8","followers_url":"https://api.github.com/users/roelens8/followers","following_url":"https://api.github.com/users/roelens8/following{/other_user}","gists_url":"https://api.github.com/users/roelens8/gists{/gist_id}","starred_url":"https://api.github.com/users/roelens8/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/roelens8/subscriptions","organizations_url":"https://api.github.com/users/roelens8/orgs","repos_url":"https://api.github.com/users/roelens8/repos","events_url":"https://api.github.com/users/roelens8/events{/privacy}","received_events_url":"https://api.github.com/users/roelens8/received_events","type":"User","site_admin":false},"repo":{"id":37481426,"name":"ddf","full_name":"roelens8/ddf","owner":{"login":"roelens8","id":5935039,"avatar_url":"https://avatars.githubusercontent.com/u/5935039?v=3","gravatar_id":"","url":"https://api.github.com/users/roelens8","html_url":"https://github.com/roelens8","followers_url":"https://api.github.com/users/roelens8/followers","following_url":"https://api.github.com/users/roelens8/following{/other_user}","gists_url":"https://api.github.com/users/roelens8/gists{/gist_id}","starred_url":"https://api.github.com/users/roelens8/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/roelens8/subscriptions","organizations_url":"https://api.github.com/users/roelens8/orgs","repos_url":"https://api.github.com/users/roelens8/repos","events_url":"https://api.github.com/users/roelens8/events{/privacy}","received_events_url":"https://api.github.com/users/roelens8/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/roelens8/ddf","description":"The Distributed Data Framework - Distribution, SDK, and Test","fork":true,"url":"https://api.github.com/repos/roelens8/ddf","forks_url":"https://api.github.com/repos/roelens8/ddf/forks","keys_url":"https://api.github.com/repos/roelens8/ddf/keys{/key_id}","collaborators_url":"https://api.github.com/repos/roelens8/ddf/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/roelens8/ddf/teams","hooks_url":"https://api.github.com/repos/roelens8/ddf/hooks","issue_events_url":"https://api.github.com/repos/roelens8/ddf/issues/events{/number}","events_url":"https://api.github.com/repos/roelens8/ddf/events","assignees_url":"https://api.github.com/repos/roelens8/ddf/assignees{/user}","branches_url":"https://api.github.com/repos/roelens8/ddf/branches{/branch}","tags_url":"https://api.github.com/repos/roelens8/ddf/tags","blobs_url":"https://api.github.com/repos/roelens8/ddf/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/roelens8/ddf/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/roelens8/ddf/git/refs{/sha}","trees_url":"https://api.github.com/repos/roelens8/ddf/git/trees{/sha}","statuses_url":"https://api.github.com/repos/roelens8/ddf/statuses/{sha}","languages_url":"https://api.github.com/repos/roelens8/ddf/languages","stargazers_url":"https://api.github.com/repos/roelens8/ddf/stargazers","contributors_url":"https://api.github.com/repos/roelens8/ddf/contributors","subscribers_url":"https://api.github.com/repos/roelens8/ddf/subscribers","subscription_url":"https://api.github.com/repos/roelens8/ddf/subscription","commits_url":"https://api.github.com/repos/roelens8/ddf/commits{/sha}","git_commits_url":"https://api.github.com/repos/roelens8/ddf/git/commits{/sha}","comments_url":"https://api.github.com/repos/roelens8/ddf/comments{/number}","issue_comment_url":"https://api.github.com/repos/roelens8/ddf/issues/comments{/number}","contents_url":"https://api.github.com/repos/roelens8/ddf/contents/{+path}","compare_url":"https://api.github.com/repos/roelens8/ddf/compare/{base}...{head}","merges_url":"https://api.github.com/repos/roelens8/ddf/merges","archive_url":"https://api.github.com/repos/roelens8/ddf/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/roelens8/ddf/downloads","issues_url":"https://api.github.com/repos/roelens8/ddf/issues{/number}","pulls_url":"https://api.github.com/repos/roelens8/ddf/pulls{/number}","milestones_url":"https://api.github.com/repos/roelens8/ddf/milestones{/number}","notifications_url":"https://api.github.com/repos/roelens8/ddf/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/roelens8/ddf/labels{/name}","releases_url":"https://api.github.com/repos/roelens8/ddf/releases{/id}","deployments_url":"https://api.github.com/repos/roelens8/ddf/deployments","created_at":"2015-06-15T17:55:32Z","updated_at":"2015-06-15T17:55:33Z","pushed_at":"2016-04-15T21:09:36Z","git_url":"git://github.com/roelens8/ddf.git","ssh_url":"git@github.com:roelens8/ddf.git","clone_url":"https://github.com/roelens8/ddf.git","svn_url":"https://github.com/roelens8/ddf","homepage":"","size":140978,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"codice:master","ref":"master","sha":"4e51a281c52d499c237b6636f94947c7838f8612","user":{"login":"codice","id":2386734,"avatar_url":"https://avatars.githubusercontent.com/u/2386734?v=3","gravatar_id":"","url":"https://api.github.com/users/codice","html_url":"https://github.com/codice","followers_url":"https://api.github.com/users/codice/followers","following_url":"https://api.github.com/users/codice/following{/other_user}","gists_url":"https://api.github.com/users/codice/gists{/gist_id}","starred_url":"https://api.github.com/users/codice/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/codice/subscriptions","organizations_url":"https://api.github.com/users/codice/orgs","repos_url":"https://api.github.com/users/codice/repos","events_url":"https://api.github.com/users/codice/events{/privacy}","received_events_url":"https://api.github.com/users/codice/received_events","type":"Organization","site_admin":false},"repo":{"id":15173563,"name":"ddf","full_name":"codice/ddf","owner":{"login":"codice","id":2386734,"avatar_url":"https://avatars.githubusercontent.com/u/2386734?v=3","gravatar_id":"","url":"https://api.github.com/users/codice","html_url":"https://github.com/codice","followers_url":"https://api.github.com/users/codice/followers","following_url":"https://api.github.com/users/codice/following{/other_user}","gists_url":"https://api.github.com/users/codice/gists{/gist_id}","starred_url":"https://api.github.com/users/codice/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/codice/subscriptions","organizations_url":"https://api.github.com/users/codice/orgs","repos_url":"https://api.github.com/users/codice/repos","events_url":"https://api.github.com/users/codice/events{/privacy}","received_events_url":"https://api.github.com/users/codice/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/codice/ddf","description":"The Distributed Data Framework - Federated Open Geospatial Consortium (OGC) filter powered metadata catalog with SAML Web SSO secured container","fork":false,"url":"https://api.github.com/repos/codice/ddf","forks_url":"https://api.github.com/repos/codice/ddf/forks","keys_url":"https://api.github.com/repos/codice/ddf/keys{/key_id}","collaborators_url":"https://api.github.com/repos/codice/ddf/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/codice/ddf/teams","hooks_url":"https://api.github.com/repos/codice/ddf/hooks","issue_events_url":"https://api.github.com/repos/codice/ddf/issues/events{/number}","events_url":"https://api.github.com/repos/codice/ddf/events","assignees_url":"https://api.github.com/repos/codice/ddf/assignees{/user}","branches_url":"https://api.github.com/repos/codice/ddf/branches{/branch}","tags_url":"https://api.github.com/repos/codice/ddf/tags","blobs_url":"https://api.github.com/repos/codice/ddf/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/codice/ddf/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/codice/ddf/git/refs{/sha}","trees_url":"https://api.github.com/repos/codice/ddf/git/trees{/sha}","statuses_url":"https://api.github.com/repos/codice/ddf/statuses/{sha}","languages_url":"https://api.github.com/repos/codice/ddf/languages","stargazers_url":"https://api.github.com/repos/codice/ddf/stargazers","contributors_url":"https://api.github.com/repos/codice/ddf/contributors","subscribers_url":"https://api.github.com/repos/codice/ddf/subscribers","subscription_url":"https://api.github.com/repos/codice/ddf/subscription","commits_url":"https://api.github.com/repos/codice/ddf/commits{/sha}","git_commits_url":"https://api.github.com/repos/codice/ddf/git/commits{/sha}","comments_url":"https://api.github.com/repos/codice/ddf/comments{/number}","issue_comment_url":"https://api.github.com/repos/codice/ddf/issues/comments{/number}","contents_url":"https://api.github.com/repos/codice/ddf/contents/{+path}","compare_url":"https://api.github.com/repos/codice/ddf/compare/{base}...{head}","merges_url":"https://api.github.com/repos/codice/ddf/merges","archive_url":"https://api.github.com/repos/codice/ddf/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/codice/ddf/downloads","issues_url":"https://api.github.com/repos/codice/ddf/issues{/number}","pulls_url":"https://api.github.com/repos/codice/ddf/pulls{/number}","milestones_url":"https://api.github.com/repos/codice/ddf/milestones{/number}","notifications_url":"https://api.github.com/repos/codice/ddf/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/codice/ddf/labels{/name}","releases_url":"https://api.github.com/repos/codice/ddf/releases{/id}","deployments_url":"https://api.github.com/repos/codice/ddf/deployments","created_at":"2013-12-13T20:38:28Z","updated_at":"2016-04-10T11:25:35Z","pushed_at":"2016-04-15T21:19:08Z","git_url":"git://github.com/codice/ddf.git","ssh_url":"git@github.com:codice/ddf.git","clone_url":"https://github.com/codice/ddf.git","svn_url":"https://github.com/codice/ddf","homepage":"","size":156910,"stargazers_count":37,"watchers_count":37,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":74,"mirror_url":null,"open_issues_count":17,"forks":74,"open_issues":17,"watchers":37,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/codice/ddf/pulls/706"},"html":{"href":"https://github.com/codice/ddf/pull/706"},"issue":{"href":"https://api.github.com/repos/codice/ddf/issues/706"},"comments":{"href":"https://api.github.com/repos/codice/ddf/issues/706/comments"},"review_comments":{"href":"https://api.github.com/repos/codice/ddf/pulls/706/comments"},"review_comment":{"href":"https://api.github.com/repos/codice/ddf/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/codice/ddf/pulls/706/commits"},"statuses":{"href":"https://api.github.com/repos/codice/ddf/statuses/2141ed3ffd826deb300a29218847666036199b39"}}}}