1 package edu.internet2.middleware.grouper.authentication.plugin;
2
3 import edu.internet2.middleware.grouper.authentication.plugin.config.ClientProvider;
4 import edu.internet2.middleware.grouper.authentication.plugin.config.ClientProviders;
5 import edu.internet2.middleware.grouperClient.config.ConfigPropertiesCascadeBase;
6 import org.apache.commons.lang3.StringUtils;
7 import org.apache.commons.logging.Log;
8 import org.pac4j.core.client.Client;
9 import org.pac4j.core.client.Clients;
10 import org.pac4j.core.config.Config;
11 import org.pac4j.core.config.ConfigFactory;
12 import org.pac4j.core.matching.matcher.PathMatcher;
13
14 import java.lang.reflect.InvocationTargetException;
15
16 public class Pac4jConfigFactory implements ConfigFactory {
17 private static final Log LOGGER = GrouperAuthentication.getLogFactory().getInstance(Pac4jConfigFactory.class);
18
19 @Override
20 public Config build(Object... parameters) {
21 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
22 try {
23 Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
24
25 ConfigPropertiesCascadeBase grouperConfig = ConfigUtils.getBestGrouperConfiguration();
26
27 String provider;
28 if (grouperConfig.containsKey("external.authentication.mechanism")) {
29 LOGGER.warn("you're using the deprecated key `external.authentication.mechanism`; please update to `external.authentication.provider`");
30 provider = grouperConfig.propertyValueString("external.authentication.mechanism");
31 } else {
32 provider = grouperConfig.propertyValueString("external.authentication.provider");
33 }
34
35 if (StringUtils.isBlank(provider)) {
36 String configFile = ConfigUtils.isGrouperUi() ? "grouper-ui.properties" : "grouper-ws.properties";
37 throw new RuntimeException("External authentication is enabled (grouper.is.extAuth.enabled = true) "
38 + "but the required property 'external.authentication.provider' is not configured. "
39 + "Please set 'external.authentication.provider' to one of: cas, oidc, saml "
40 + "(or a fully qualified class name implementing ClientProvider) "
41 + "in " + configFile + ". "
42 + "If you do not need external authentication, set 'grouper.is.extAuth.enabled' to false "
43 + "in " + configFile + ".");
44 }
45
46 Client client = getClient(provider);
47
48 String callbackUrl = grouperConfig.propertyValueString("external.authentication.grouperContextUrl")
49 + grouperConfig.propertyValueString("external.authentication.callbackUrl", "/callback");
50 final Clients clients = new Clients(callbackUrl, client);
51
52 final Config config = new Config(clients);
53
54 PathMatcher pathMatcher = new PathMatcher();
55
56 String securityExclusionsPaths = grouperConfig.propertyValueString("external.authentication.exclusions", "/status");
57 if (securityExclusionsPaths != null) {
58 for (String exclusion : securityExclusionsPaths.split(",")) {
59 pathMatcher.excludeBranch(StringUtils.trim(exclusion));
60 }
61 }
62 config.addMatcher("securityExclusions", pathMatcher);
63 return config;
64 } catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
65 throw new RuntimeException("problem configuring pac4j", e);
66 } finally {
67 Thread.currentThread().setContextClassLoader(classLoader);
68 }
69 }
70
71
72 @SuppressWarnings("unchecked")
73 private static Client getClient(String provider) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
74 Class<? extends ClientProvider> providerClass;
75
76 try {
77 providerClass = ClientProviders.fromString(provider).getProviderClass();
78 } catch (IllegalArgumentException e) {
79 try {
80 providerClass = (Class<? extends ClientProvider>) Class.forName(provider);
81 } catch (ClassNotFoundException classNotFoundException) {
82 throw new RuntimeException(classNotFoundException);
83 }
84 }
85 return providerClass.getDeclaredConstructor().newInstance().getClient();
86 }
87 }