1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * See LICENSE.txt included in this distribution for the specific 9 * language governing permissions and limitations under the License. 10 * 11 * When distributing Covered Code, include this CDDL HEADER in each 12 * file and include the License file at LICENSE.txt. 13 * If applicable, add the following below this CDDL HEADER, with the 14 * fields enclosed by brackets "[]" replaced with your own identifying 15 * information: Portions Copyright [yyyy] [name of copyright owner] 16 * 17 * CDDL HEADER END 18 */ 19 20 /* 21 * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. 22 */ 23 package opengrok.auth.plugin; 24 25 import java.io.File; 26 import java.io.FileOutputStream; 27 import java.io.IOException; 28 import java.io.OutputStreamWriter; 29 import java.io.Writer; 30 import java.nio.file.Files; 31 import java.util.Arrays; 32 import java.util.Collections; 33 import java.util.HashMap; 34 import java.util.Map; 35 import java.util.Set; 36 import java.util.TreeMap; 37 import java.util.TreeSet; 38 39 import jakarta.servlet.http.HttpServletRequest; 40 import opengrok.auth.entity.LdapUser; 41 import opengrok.auth.plugin.entity.User; 42 import opengrok.auth.plugin.ldap.AbstractLdapProvider; 43 import opengrok.auth.plugin.ldap.FakeLdapFacade; 44 import opengrok.auth.plugin.ldap.LdapException; 45 import opengrok.auth.plugin.ldap.LdapFacade; 46 import opengrok.auth.plugin.util.DummyHttpServletRequestLdap; 47 import org.junit.jupiter.api.AfterAll; 48 import org.junit.jupiter.api.BeforeAll; 49 import org.junit.jupiter.api.BeforeEach; 50 import org.junit.jupiter.api.Test; 51 import org.opengrok.indexer.configuration.Group; 52 import org.opengrok.indexer.configuration.Project; 53 54 import static org.junit.jupiter.api.Assertions.assertFalse; 55 import static org.junit.jupiter.api.Assertions.assertNotNull; 56 import static org.junit.jupiter.api.Assertions.assertTrue; 57 import static org.mockito.ArgumentMatchers.any; 58 import static org.mockito.ArgumentMatchers.anyString; 59 import static org.mockito.Mockito.mock; 60 import static org.mockito.Mockito.when; 61 62 public class LdapAttrPluginTest { 63 64 private HttpServletRequest dummyRequest; 65 private LdapAttrPlugin plugin; 66 67 private static File whitelistFile; 68 69 @BeforeAll beforeClass()70 public static void beforeClass() throws IOException { 71 whitelistFile = Files.createTempFile("opengrok-auth-", "-check.tmp").toFile(); 72 try (Writer w = new OutputStreamWriter(new FileOutputStream(whitelistFile))) { 73 w.append("james@bond.com\n"); 74 w.append("random@email.com\n"); 75 w.append("just_a_text\n"); 76 } 77 } 78 79 @AfterAll afterClass()80 public static void afterClass() { 81 whitelistFile.deleteOnExit(); 82 } 83 84 @BeforeEach setUp()85 public void setUp() { 86 plugin = new LdapAttrPlugin(); 87 Map<String, Object> parameters = new TreeMap<>(); 88 89 parameters.put(LdapAttrPlugin.FILE_PARAM, whitelistFile.getAbsolutePath()); 90 parameters.put(LdapAttrPlugin.ATTR_PARAM, "mail"); 91 92 plugin.load(parameters, new FakeLdapFacade()); 93 } 94 prepareRequest(String username, String mail, String... ous)95 private void prepareRequest(String username, String mail, String... ous) { 96 dummyRequest = new DummyHttpServletRequestLdap(); 97 dummyRequest.setAttribute(UserPlugin.REQUEST_ATTR, 98 new User(username, "123")); 99 100 LdapUser ldapUser = new LdapUser(); 101 ldapUser.setAttribute("mail", new TreeSet<>(Collections.singletonList(mail))); 102 ldapUser.setAttribute("uid", new TreeSet<>(Collections.singletonList("123"))); 103 ldapUser.setAttribute("ou", new TreeSet<>(Arrays.asList(ous))); 104 105 dummyRequest.getSession().setAttribute(LdapUserPlugin.SESSION_ATTR, ldapUser); 106 plugin.setSessionEstablished(dummyRequest, true); 107 plugin.setSessionUsername(dummyRequest, username); 108 } 109 makeProject(String name)110 private Project makeProject(String name) { 111 Project p = new Project(); 112 p.setName(name); 113 return p; 114 } 115 makeGroup(String name)116 private Group makeGroup(String name) { 117 Group p = new Group(); 118 p.setName(name); 119 return p; 120 } 121 122 /** 123 * Test of {@code isAllowed} method. 124 */ 125 @Test testIsAllowed()126 void testIsAllowed() { 127 /* 128 * whitelist[mail] => [james@bond.com, random@email.com, just_a_text] 129 */ 130 prepareRequest("007", "james@bond.com", "MI6", "MI7"); 131 132 assertTrue(plugin.isAllowed(dummyRequest, makeProject("Random Project"))); 133 assertTrue(plugin.isAllowed(dummyRequest, makeProject("Project 1"))); 134 assertTrue(plugin.isAllowed(dummyRequest, makeGroup("Group 1"))); 135 assertTrue(plugin.isAllowed(dummyRequest, makeGroup("Group 2"))); 136 137 prepareRequest("008", "james@bond.com", "MI6", "MI7"); 138 139 assertTrue(plugin.isAllowed(dummyRequest, makeProject("Random Project"))); 140 assertTrue(plugin.isAllowed(dummyRequest, makeProject("Project 1"))); 141 assertTrue(plugin.isAllowed(dummyRequest, makeGroup("Group 1"))); 142 assertTrue(plugin.isAllowed(dummyRequest, makeGroup("Group 2"))); 143 144 prepareRequest("009", "other@email.com", "MI6"); 145 146 assertFalse(plugin.isAllowed(dummyRequest, makeProject("Random Project"))); 147 assertFalse(plugin.isAllowed(dummyRequest, makeProject("Project 1"))); 148 assertFalse(plugin.isAllowed(dummyRequest, makeGroup("Group 1"))); 149 assertFalse(plugin.isAllowed(dummyRequest, makeGroup("Group 2"))); 150 151 prepareRequest("00A", "random@email.com", "MI6", "MI7"); 152 153 assertTrue(plugin.isAllowed(dummyRequest, makeProject("Random Project"))); 154 assertTrue(plugin.isAllowed(dummyRequest, makeProject("Project 1"))); 155 assertTrue(plugin.isAllowed(dummyRequest, makeGroup("Group 1"))); 156 assertTrue(plugin.isAllowed(dummyRequest, makeGroup("Group 2"))); 157 } 158 159 /** 160 * Test the interaction between {@code LdapUserPlugin} and {@code LdapAttrPlugin}. Namely: 161 * <ul> 162 * <li>use of DN from the <code>LdapUser</code> object cached in the session by <code>LdapUserPlugin</code></li> 163 * <li>configuration of the cached session attribute name</li> 164 * </ul> 165 */ 166 @Test testAttrLookup()167 void testAttrLookup() throws LdapException { 168 String attr_to_get = "mail"; 169 String instance_num = "42"; 170 String mail_attr_value = "james@bond.com"; 171 172 // Create mock LDAP provider, simulating the work of LDAP server for LdapAttrPlugin#fillSession(). 173 AbstractLdapProvider mockProvider = mock(LdapFacade.class); 174 Map<String, Set<String>> attrs = new HashMap<>(); 175 attrs.put(attr_to_get, Collections.singleton(mail_attr_value)); 176 final String dn = "cn=FOO_BAR,L=EMEA,DC=FOO,DC=COM"; 177 AbstractLdapProvider.LdapSearchResult<Map<String, Set<String>>> result = 178 new AbstractLdapProvider.LdapSearchResult<>(dn, attrs); 179 assertNotNull(result); 180 when(mockProvider.lookupLdapContent(anyString(), any(String[].class))).thenReturn(result); 181 182 // Load the LdapAttrPlugin using the mock LDAP provider. 183 LdapAttrPlugin plugin = new LdapAttrPlugin(); 184 Map<String, Object> parameters = new TreeMap<>(); 185 parameters.put(LdapAttrPlugin.FILE_PARAM, whitelistFile.getAbsolutePath()); 186 parameters.put(LdapAttrPlugin.ATTR_PARAM, attr_to_get); 187 parameters.put(LdapAttrPlugin.INSTANCE_PARAM, instance_num); 188 plugin.load(parameters, mockProvider); 189 190 LdapUser ldapUser = new LdapUser(dn, null); 191 HttpServletRequest request = new DummyHttpServletRequestLdap(); 192 request.getSession().setAttribute(LdapUserPlugin.SESSION_ATTR + instance_num, ldapUser); 193 194 // Here it comes all together. 195 User user = new User("jbond", "007"); 196 plugin.fillSession(request, user); 197 198 // See if LdapAttrPlugin set its own session attribute based on the mocked query. 199 assertTrue((Boolean) request.getSession().getAttribute(plugin.getSessionAllowedAttrName())); 200 assertTrue(ldapUser.getAttribute(attr_to_get).contains(mail_attr_value)); 201 } 202 } 203