1b28a5538SAdam Hornacek /* 2b28a5538SAdam Hornacek * CDDL HEADER START 3b28a5538SAdam Hornacek * 4b28a5538SAdam Hornacek * The contents of this file are subject to the terms of the 5b28a5538SAdam Hornacek * Common Development and Distribution License (the "License"). 6b28a5538SAdam Hornacek * You may not use this file except in compliance with the License. 7b28a5538SAdam Hornacek * 8b28a5538SAdam Hornacek * See LICENSE.txt included in this distribution for the specific 9b28a5538SAdam Hornacek * language governing permissions and limitations under the License. 10b28a5538SAdam Hornacek * 11b28a5538SAdam Hornacek * When distributing Covered Code, include this CDDL HEADER in each 12b28a5538SAdam Hornacek * file and include the License file at LICENSE.txt. 13b28a5538SAdam Hornacek * If applicable, add the following below this CDDL HEADER, with the 14b28a5538SAdam Hornacek * fields enclosed by brackets "[]" replaced with your own identifying 15b28a5538SAdam Hornacek * information: Portions Copyright [yyyy] [name of copyright owner] 16b28a5538SAdam Hornacek * 17b28a5538SAdam Hornacek * CDDL HEADER END 18b28a5538SAdam Hornacek */ 19b28a5538SAdam Hornacek 20b28a5538SAdam Hornacek /* 21ee1fba58SVladimir Kotal * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. 22895b87d2SChris Fraire * Portions Copyright (c) 2020, Chris Fraire <cfraire@me.com>. 23b28a5538SAdam Hornacek */ 24b28a5538SAdam Hornacek package opengrok.auth.plugin; 25b28a5538SAdam Hornacek 26aa6abf42SAdam Hornacek import jakarta.servlet.http.HttpServletRequest; 27b28a5538SAdam Hornacek import opengrok.auth.plugin.entity.User; 28cdc7fb8fSVladimir Kotal import org.jetbrains.annotations.TestOnly; 29b28a5538SAdam Hornacek import org.opengrok.indexer.authorization.IAuthorizationPlugin; 30b28a5538SAdam Hornacek import org.opengrok.indexer.configuration.Group; 31b28a5538SAdam Hornacek import org.opengrok.indexer.configuration.Project; 32b28a5538SAdam Hornacek 33b28a5538SAdam Hornacek import java.io.IOException; 34b28a5538SAdam Hornacek import java.nio.file.Files; 35b28a5538SAdam Hornacek import java.nio.file.Paths; 36b28a5538SAdam Hornacek import java.util.Map; 37b28a5538SAdam Hornacek import java.util.Set; 38b28a5538SAdam Hornacek import java.util.TreeSet; 39b28a5538SAdam Hornacek import java.util.logging.Level; 40b28a5538SAdam Hornacek import java.util.logging.Logger; 41b28a5538SAdam Hornacek import java.util.stream.Stream; 42b28a5538SAdam Hornacek 43b28a5538SAdam Hornacek public class UserWhiteListPlugin implements IAuthorizationPlugin { 449d74bf96SVladimir Kotal private static final String CLASS_NAME = UserWhiteListPlugin.class.getName(); 459d74bf96SVladimir Kotal private static final Logger LOGGER = Logger.getLogger(CLASS_NAME); 46b28a5538SAdam Hornacek 471f3b8d68SVladimir Kotal // configuration parameters 48895b87d2SChris Fraire static final String FILE_PARAM = "file"; 491f3b8d68SVladimir Kotal static final String FIELD_PARAM = "fieldName"; 501f3b8d68SVladimir Kotal 511f3b8d68SVladimir Kotal // valid values for the FIELD_NAME parameter 521f3b8d68SVladimir Kotal static final String USERNAME_FIELD = "username"; 531f3b8d68SVladimir Kotal static final String ID_FIELD = "id"; 54b28a5538SAdam Hornacek 55b28a5538SAdam Hornacek private final Set<String> whitelist = new TreeSet<>(); 561f3b8d68SVladimir Kotal private String fieldName; 57b28a5538SAdam Hornacek 58b28a5538SAdam Hornacek @Override load(Map<String, Object> parameters)59b28a5538SAdam Hornacek public void load(Map<String, Object> parameters) { 60*4ceb1b98SVladimir Kotal if (parameters == null) { 61*4ceb1b98SVladimir Kotal throw new IllegalArgumentException("Null parameter"); 62*4ceb1b98SVladimir Kotal } 63*4ceb1b98SVladimir Kotal 64b28a5538SAdam Hornacek String filePath; 65b28a5538SAdam Hornacek if ((filePath = (String) parameters.get(FILE_PARAM)) == null) { 66895b87d2SChris Fraire throw new IllegalArgumentException("Missing parameter [" + FILE_PARAM + "] in the configuration"); 67b28a5538SAdam Hornacek } 68b28a5538SAdam Hornacek 691f3b8d68SVladimir Kotal if ((fieldName = (String) parameters.get(FIELD_PARAM)) == null) { 701f3b8d68SVladimir Kotal fieldName = USERNAME_FIELD; 711f3b8d68SVladimir Kotal } else if (!fieldName.equals(USERNAME_FIELD) && !fieldName.equals(ID_FIELD)) { 721f3b8d68SVladimir Kotal throw new IllegalArgumentException("Invalid value of parameter [" + FIELD_PARAM + 731f3b8d68SVladimir Kotal "] in the configuration: only " + USERNAME_FIELD + " or " + ID_FIELD + " are supported"); 741f3b8d68SVladimir Kotal } 751f3b8d68SVladimir Kotal 76b28a5538SAdam Hornacek // Load whitelist from file to memory. 77b28a5538SAdam Hornacek try (Stream<String> stream = Files.lines(Paths.get(filePath))) { 78ee1fba58SVladimir Kotal stream.map(String::strip).forEach(whitelist::add); 79b28a5538SAdam Hornacek } catch (IOException e) { 80b28a5538SAdam Hornacek throw new IllegalArgumentException(String.format("Unable to read the file \"%s\"", filePath), e); 81b28a5538SAdam Hornacek } 82dd7c760cSVladimir Kotal 83dd7c760cSVladimir Kotal LOGGER.log(Level.FINE, "UserWhiteList plugin loaded with filePath={0} ({1} entries), fieldName={2}", 84dd7c760cSVladimir Kotal new Object[]{filePath, whitelist.size(), fieldName}); 85b28a5538SAdam Hornacek } 86b28a5538SAdam Hornacek 87cdc7fb8fSVladimir Kotal @TestOnly getWhitelist()88ee1fba58SVladimir Kotal Set<String> getWhitelist() { 89ee1fba58SVladimir Kotal return whitelist; 90ee1fba58SVladimir Kotal } 91ee1fba58SVladimir Kotal 92b28a5538SAdam Hornacek @Override unload()93b28a5538SAdam Hornacek public void unload() { 94b28a5538SAdam Hornacek whitelist.clear(); 95b28a5538SAdam Hornacek } 96b28a5538SAdam Hornacek checkWhitelist(HttpServletRequest request)97b28a5538SAdam Hornacek private boolean checkWhitelist(HttpServletRequest request) { 98b28a5538SAdam Hornacek User user; 99b28a5538SAdam Hornacek String attrName = UserPlugin.REQUEST_ATTR; 100b28a5538SAdam Hornacek if ((user = (User) request.getAttribute(attrName)) == null) { 1019ae4322aSVladimir Kotal LOGGER.log(Level.WARNING, "cannot get {0} attribute", attrName); 102b28a5538SAdam Hornacek return false; 103b28a5538SAdam Hornacek } 104b28a5538SAdam Hornacek 1051f3b8d68SVladimir Kotal if (fieldName.equals(USERNAME_FIELD)) { 1061f3b8d68SVladimir Kotal return user.getUsername() != null && whitelist.contains(user.getUsername()); 1071f3b8d68SVladimir Kotal } else if (fieldName.equals(ID_FIELD)) { 1081f3b8d68SVladimir Kotal return user.getId() != null && whitelist.contains(user.getId()); 1091f3b8d68SVladimir Kotal } 1101f3b8d68SVladimir Kotal 1111f3b8d68SVladimir Kotal return false; 112b28a5538SAdam Hornacek } 113b28a5538SAdam Hornacek 114b28a5538SAdam Hornacek @Override isAllowed(HttpServletRequest request, Project project)115b28a5538SAdam Hornacek public boolean isAllowed(HttpServletRequest request, Project project) { 116b28a5538SAdam Hornacek return checkWhitelist(request); 117b28a5538SAdam Hornacek } 118b28a5538SAdam Hornacek 119b28a5538SAdam Hornacek @Override isAllowed(HttpServletRequest request, Group group)120b28a5538SAdam Hornacek public boolean isAllowed(HttpServletRequest request, Group group) { 121b28a5538SAdam Hornacek return checkWhitelist(request); 122b28a5538SAdam Hornacek } 123b28a5538SAdam Hornacek } 124