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) 2020, Chris Fraire <cfraire@me.com>. 22 * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. 23 */ 24 package opengrok.auth.plugin; 25 26 import opengrok.auth.plugin.entity.User; 27 import org.apache.commons.lang3.RandomStringUtils; 28 import org.junit.jupiter.api.AfterAll; 29 import org.junit.jupiter.api.BeforeAll; 30 import org.junit.jupiter.params.ParameterizedTest; 31 import org.junit.jupiter.params.provider.MethodSource; 32 import org.opengrok.indexer.configuration.Group; 33 import org.opengrok.indexer.configuration.Project; 34 import org.opengrok.indexer.web.DummyHttpServletRequest; 35 36 import java.io.BufferedWriter; 37 import java.io.File; 38 import java.io.FileOutputStream; 39 import java.io.IOException; 40 import java.io.OutputStreamWriter; 41 import java.io.PrintWriter; 42 import java.nio.charset.StandardCharsets; 43 import java.nio.file.Files; 44 import java.util.Arrays; 45 import java.util.Collection; 46 import java.util.HashMap; 47 import java.util.Map; 48 import java.util.Set; 49 import java.util.stream.Collectors; 50 import java.util.stream.Stream; 51 52 import static org.junit.jupiter.api.Assertions.assertEquals; 53 import static org.junit.jupiter.api.Assertions.assertFalse; 54 import static org.junit.jupiter.api.Assertions.assertNotNull; 55 import static org.junit.jupiter.api.Assertions.assertThrows; 56 import static org.junit.jupiter.api.Assertions.assertTrue; 57 58 /** 59 * Represents a container for tests of {@link UserWhiteListPlugin}. 60 */ 61 public class UserWhiteListPluginTest { 62 63 private static final String OK_USER = "user1321"; 64 private static final String OK_ID = "id2178"; 65 private static File tempWhitelistUser; 66 private static File tempWhitelistId; 67 private static HashMap<String, Object> validPluginParameters; 68 69 private UserWhiteListPlugin plugin; 70 parameters()71 public static Collection<String> parameters() { 72 return Arrays.asList(UserWhiteListPlugin.ID_FIELD, UserWhiteListPlugin.USERNAME_FIELD); 73 } 74 75 @BeforeAll beforeClass()76 public static void beforeClass() throws Exception { 77 tempWhitelistUser = File.createTempFile("UserWhiteListPluginTestUser", "txt"); 78 try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter( 79 new FileOutputStream(tempWhitelistUser), StandardCharsets.UTF_8))) { 80 writer.write(OK_USER); 81 // Don't bother with trailing LF. 82 } 83 84 tempWhitelistId = File.createTempFile("UserWhiteListPluginTestId", "txt"); 85 try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter( 86 new FileOutputStream(tempWhitelistId), StandardCharsets.UTF_8))) { 87 writer.write(OK_ID); 88 // Don't bother with trailing LF. 89 } 90 91 validPluginParameters = new HashMap<>(); 92 } 93 94 @AfterAll afterClass()95 public static void afterClass() { 96 if (tempWhitelistUser != null) { 97 //noinspection ResultOfMethodCallIgnored 98 tempWhitelistUser.delete(); 99 } 100 if (tempWhitelistId != null) { 101 //noinspection ResultOfMethodCallIgnored 102 tempWhitelistId.delete(); 103 } 104 } 105 init(String param)106 public void init(String param) { 107 plugin = new UserWhiteListPlugin(); 108 validPluginParameters.put(UserWhiteListPlugin.FIELD_PARAM, param); 109 if (param.equals(UserWhiteListPlugin.USERNAME_FIELD)) { 110 validPluginParameters.put(UserWhiteListPlugin.FILE_PARAM, tempWhitelistUser.getPath()); 111 } else { 112 validPluginParameters.put(UserWhiteListPlugin.FILE_PARAM, tempWhitelistId.getPath()); 113 } 114 } 115 116 @ParameterizedTest 117 @MethodSource("parameters") shouldThrowOnLoadIfNullArgument(String param)118 public void shouldThrowOnLoadIfNullArgument(String param) { 119 init(param); 120 assertThrows(IllegalArgumentException.class, () -> { 121 //noinspection ConstantConditions 122 plugin.load(null); 123 }, "plugin.load(null)"); 124 } 125 126 @ParameterizedTest 127 @MethodSource("parameters") shouldThrowOnLoadIfInvalidFieldName(String param)128 public void shouldThrowOnLoadIfInvalidFieldName(String param) { 129 init(param); 130 assertThrows(IllegalArgumentException.class, () -> { 131 Map<String, Object> map = new HashMap<>(); 132 map.put(UserWhiteListPlugin.FILE_PARAM, tempWhitelistUser.getPath()); 133 map.put(UserWhiteListPlugin.FIELD_PARAM, "huh"); 134 plugin.load(map); 135 }, "plugin.load(null)"); 136 } 137 138 @ParameterizedTest 139 @MethodSource("parameters") shouldThrowOnLoadIfUnreadableFileSpecified(String param)140 public void shouldThrowOnLoadIfUnreadableFileSpecified(String param) { 141 init(param); 142 HashMap<String, Object> unreadablePluginParameters = new HashMap<>(); 143 unreadablePluginParameters.put(UserWhiteListPlugin.FILE_PARAM, 144 RandomStringUtils.randomAlphanumeric(24)); 145 146 IllegalArgumentException caughtException = null; 147 try { 148 plugin.load(unreadablePluginParameters); 149 } catch (IllegalArgumentException ex) { 150 caughtException = ex; 151 } 152 153 assertNotNull(caughtException, "caught IllegalArgumentException"); 154 assertTrue(caughtException.getMessage().contains("Unable to read the file"), 155 "caughtException should mention 'Unable to read the file'"); 156 } 157 158 @ParameterizedTest 159 @MethodSource("parameters") shouldThrowOnLoadIfNoFileSpecified(String param)160 public void shouldThrowOnLoadIfNoFileSpecified(String param) { 161 init(param); 162 IllegalArgumentException caughtException = null; 163 try { 164 plugin.load(new HashMap<>()); 165 } catch (IllegalArgumentException ex) { 166 caughtException = ex; 167 } 168 169 assertNotNull(caughtException, "caught IllegalArgumentException"); 170 assertTrue(caughtException.getMessage().contains("Missing parameter"), 171 "caughtException should mention 'Missing parameter'"); 172 } 173 174 @ParameterizedTest 175 @MethodSource("parameters") shouldStripWhitespaceFromWhitelists(String param)176 public void shouldStripWhitespaceFromWhitelists(String param) throws IOException { 177 plugin = new UserWhiteListPlugin(); 178 HashMap<String, Object> pluginParameters = new HashMap<>(); 179 pluginParameters.put(UserWhiteListPlugin.FIELD_PARAM, param); 180 Set<String> entries = Set.of("Moomin", " Fillyjonk", " Snuffkin", "Snork Maiden ", "Groke "); 181 182 File tmpFile = File.createTempFile("UserWhiteListPluginTestId", "txt"); 183 try (PrintWriter writer = new PrintWriter(new OutputStreamWriter( 184 new FileOutputStream(tmpFile), StandardCharsets.UTF_8))) { 185 for (String entity : entries) { 186 writer.println(entity); 187 } 188 } 189 190 // Make sure there as some entries with trailing spaces in the file. 191 Stream<String> stream = Files.lines(tmpFile.toPath()); 192 assertTrue(stream.filter(s -> s.startsWith(" ") || s.endsWith(" ")). 193 collect(Collectors.toSet()).size() > 0); 194 195 pluginParameters.put(UserWhiteListPlugin.FILE_PARAM, tmpFile.toString()); 196 plugin.load(pluginParameters); 197 tmpFile.delete(); 198 199 Set<String> expected = entries.stream().map(String::trim).collect(Collectors.toSet()); 200 assertEquals(expected, plugin.getWhitelist()); 201 } 202 203 @ParameterizedTest 204 @MethodSource("parameters") shouldUnload(String param)205 public void shouldUnload(String param) { 206 init(param); 207 plugin.unload(); 208 } 209 210 @ParameterizedTest 211 @MethodSource("parameters") shouldAllowWhitelistedUserForAnyProject(String param)212 public void shouldAllowWhitelistedUserForAnyProject(String param) { 213 init(param); 214 plugin.load(validPluginParameters); 215 216 DummyHttpServletRequest req = new DummyHttpServletRequest(); 217 User user; 218 if (param.equals(UserWhiteListPlugin.USERNAME_FIELD)) { 219 user = new User(OK_USER); 220 } else { 221 user = new User("blurb", OK_ID); 222 } 223 req.setAttribute(UserPlugin.REQUEST_ATTR, user); 224 225 Project randomProject = new Project(RandomStringUtils.randomAlphanumeric(10)); 226 boolean projectAllowed = plugin.isAllowed(req, randomProject); 227 assertTrue(projectAllowed, "should allow OK entity for random project 1"); 228 229 randomProject = new Project(RandomStringUtils.randomAlphanumeric(10)); 230 projectAllowed = plugin.isAllowed(req, randomProject); 231 assertTrue(projectAllowed, "should allow OK entity for random project 2"); 232 } 233 234 @ParameterizedTest 235 @MethodSource("parameters") shouldNotAllowRandomUserForAnyProject(String param)236 public void shouldNotAllowRandomUserForAnyProject(String param) { 237 init(param); 238 plugin.load(validPluginParameters); 239 240 DummyHttpServletRequest req = new DummyHttpServletRequest(); 241 req.setAttribute(UserPlugin.REQUEST_ATTR, new User(RandomStringUtils.randomAlphanumeric(8))); 242 243 Project randomProject = new Project(RandomStringUtils.randomAlphanumeric(10)); 244 boolean projectAllowed = plugin.isAllowed(req, randomProject); 245 assertFalse(projectAllowed, "should not allow random user for random project 1"); 246 247 randomProject = new Project(RandomStringUtils.randomAlphanumeric(10)); 248 projectAllowed = plugin.isAllowed(req, randomProject); 249 assertFalse(projectAllowed, "should not allow random user for random project 2"); 250 } 251 252 @ParameterizedTest 253 @MethodSource("parameters") shouldAllowWhitelistedUserForAnyGroup(String param)254 public void shouldAllowWhitelistedUserForAnyGroup(String param) { 255 init(param); 256 plugin.load(validPluginParameters); 257 258 DummyHttpServletRequest req = new DummyHttpServletRequest(); 259 User user; 260 if (param.equals(UserWhiteListPlugin.USERNAME_FIELD)) { 261 user = new User(OK_USER); 262 } else { 263 user = new User("blurb", OK_ID); 264 } 265 req.setAttribute(UserPlugin.REQUEST_ATTR, user); 266 267 Group randomGroup = new Group(RandomStringUtils.randomAlphanumeric(10)); 268 boolean groupAllowed = plugin.isAllowed(req, randomGroup); 269 assertTrue(groupAllowed, "should allow OK entity for random group 1"); 270 271 randomGroup = new Group(RandomStringUtils.randomAlphanumeric(10)); 272 groupAllowed = plugin.isAllowed(req, randomGroup); 273 assertTrue(groupAllowed, "should allow OK entity for random group 2"); 274 } 275 276 @ParameterizedTest 277 @MethodSource("parameters") shouldNotAllowRandomUserForAnyGroup(String param)278 public void shouldNotAllowRandomUserForAnyGroup(String param) { 279 init(param); 280 plugin.load(validPluginParameters); 281 282 DummyHttpServletRequest req = new DummyHttpServletRequest(); 283 req.setAttribute(UserPlugin.REQUEST_ATTR, new User(RandomStringUtils.randomAlphanumeric(8))); 284 285 Group randomGroup = new Group(RandomStringUtils.randomAlphanumeric(10)); 286 boolean projectAllowed = plugin.isAllowed(req, randomGroup); 287 assertFalse(projectAllowed, "should not allow random group 1"); 288 289 randomGroup = new Group(RandomStringUtils.randomAlphanumeric(10)); 290 projectAllowed = plugin.isAllowed(req, randomGroup); 291 assertFalse(projectAllowed, "should not allow random group 2"); 292 } 293 } 294