xref: /OpenGrok/plugins/src/main/java/opengrok/auth/plugin/UserWhiteListPlugin.java (revision 4ceb1b98c17b7b580c0718bb27573b95081b34a5)
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