Skip to content

Commit

Permalink
[NOTASK]
Browse files Browse the repository at this point in the history
initial java code
  • Loading branch information
jj committed Aug 22, 2022
1 parent 2616122 commit 5e57087
Show file tree
Hide file tree
Showing 19 changed files with 691 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package edu.internet2.middleware.grouper.authentication.plugin;

import edu.internet2.middleware.grouper.cfg.GrouperHibernateConfig;
import edu.internet2.middleware.grouperClient.config.ConfigPropertiesCascadeBase;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.pac4j.core.client.config.BaseClientConfiguration;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.time.Period;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class ConfigUtils {
final static ResourceLoader resourceLoader = new DefaultResourceLoader();

final static BundleContext bundleContext = FrameworkUtil.getBundle(GrouperAuthentication.class).getBundleContext();

public static ConfigPropertiesCascadeBase getBestGrouperConfiguration() {
if (isGrouperUi()) {
return getConfigPropertiesCascadeBase("ui");
} else if (isGrouperWs()) {
return getConfigPropertiesCascadeBase("ws");
} else if (isGrouperDaemon()) {
return getConfigPropertiesCascadeBase("daemon");
} else {
throw new RuntimeException("no appropriate configuration found");
}
}

public static ConfigPropertiesCascadeBase getConfigPropertiesCascadeBase(String type) {
try {
ServiceReference<ConfigPropertiesCascadeBase> serviceReference = (ServiceReference<ConfigPropertiesCascadeBase>) FrameworkUtil.getBundle(ConfigUtils.class.getClassLoader()).get().getBundleContext().getServiceReferences(ConfigPropertiesCascadeBase.class, "(type=" + type + ")").toArray()[0];
return FrameworkUtil.getBundle(ConfigUtils.class.getClassLoader()).get().getBundleContext().getService(serviceReference);
} catch (InvalidSyntaxException e) {
throw new RuntimeException(e);
}
}

public static void setProperties(BaseClientConfiguration configuration, String authMechanism) {
ConfigPropertiesCascadeBase grouperConfig = getBestGrouperConfiguration();

Class<?> clazz = configuration.getClass();
for (String name : grouperConfig.propertyNames()) {
if (name.startsWith("external.authentication." + authMechanism)) {
try {
String fieldName = name.substring(name.lastIndexOf('.') + 1);
Field field = getField(clazz, fieldName);

//TODO: prefer setters

field.setAccessible(true);
field.set(configuration, getProperty(grouperConfig, field.getType(), name));
} catch (NoSuchFieldException e) {
throw new IllegalStateException("Unexpected property name: " + name);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unable to access property name: " + name);
}
}
}
}

private static Field getField(Class clazz, String name) throws NoSuchFieldException {
try {
return clazz.getDeclaredField(name);
} catch (NoSuchFieldException e) {
if (clazz.equals(Object.class)) {
throw new NoSuchFieldException(name);
}
return getField(clazz.getSuperclass(), name);
}
}

private static Object getProperty(ConfigPropertiesCascadeBase configPropertiesCascadeBase, Type type, String propName) {
switch (type.getTypeName()) {
case "java.lang.String" : {
return configPropertiesCascadeBase.propertyValueString(propName);
}
case "int" :
case "java.lang.Integer" : {
return configPropertiesCascadeBase.propertyValueInt(propName);
}
case "long" :
case "java.lang.Long" : {
return Long.parseLong(configPropertiesCascadeBase.propertyValueString(propName));
}
case "double" :
case "java.lang.Double" : {
return Double.parseDouble(configPropertiesCascadeBase.propertyValueString(propName));
}
case "boolean" :
case "java.lang.Boolean" : {
return configPropertiesCascadeBase.propertyValueBoolean(propName);
}
case "java.util.List" :
case "java.util.Collection" :{
return Arrays.asList(configPropertiesCascadeBase.propertyValueString(propName).split(","));
}
case "java.util.Set" : {
Set set = new HashSet();
for (String prop : configPropertiesCascadeBase.propertyValueString(propName).split(",")) {
set.add(prop);
}
return set;
}
case "java.util.Map" : {
Map<String, String> map = new HashMap();
for (String pairs : configPropertiesCascadeBase.propertyValueString(propName).split(",")) {
String [] keyValue = pairs.split("=");
map.put(keyValue[0].trim(),keyValue[1].trim());
}
return map;
}
case "java.time.Period" : {
return Period.parse(configPropertiesCascadeBase.propertyValueString(propName));
}
case "org.springframework.core.io.WritableResource":
case "org.springframework.core.io.Resource": {
return resourceLoader.getResource(configPropertiesCascadeBase.propertyValueString(propName));
}
default:
throw new IllegalStateException("Unexpected type: " + type.getTypeName());
}
}

public static boolean isGrouperUi() {
return getConfigPropertiesCascadeBase("hibernate").propertyValueBoolean("grouper.is.ui", false);
}

public static boolean isGrouperWs() {
return getConfigPropertiesCascadeBase("hibernate").propertyValueBoolean("grouper.is.ws", false);
}

public static boolean isGrouperDaemon() {
return getConfigPropertiesCascadeBase("hibernate").propertyValueBoolean("grouper.is.daemon", false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package edu.internet2.middleware.grouper.authentication.plugin;

import edu.internet2.middleware.grouper.authentication.plugin.filter.CallbackFilterDecorator;
import edu.internet2.middleware.grouper.authentication.plugin.filter.SecurityFilterDecorator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;

import javax.servlet.FilterRegistration;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.util.Set;

public class ExternalAuthenticationServletContainerInitializer implements ServletContainerInitializer {
private final Log log;

public ExternalAuthenticationServletContainerInitializer(BundleContext bundleContext) {
try {
//TODO: figure out why this is weird
ServiceReference<LogFactory> logfactoryReference = (ServiceReference<LogFactory>) bundleContext.getAllServiceReferences("org.apache.commons.logging.LogFactory", null)[0];
log = bundleContext.getService(logfactoryReference).getInstance(ExternalAuthenticationServletContainerInitializer.class);
} catch (InvalidSyntaxException e) {
throw new RuntimeException(e);
}
}

@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
log.info("Initializing plugin security filters for external authentication");
CallbackFilterDecorator callbackFilterDecorator = new CallbackFilterDecorator();
FilterRegistration.Dynamic callbackFilter = ctx.addFilter("callbackFilter", callbackFilterDecorator);
callbackFilter.addMappingForUrlPatterns(null, false, "/*");

SecurityFilterDecorator securityFilterDecorator = new SecurityFilterDecorator();
FilterRegistration.Dynamic securityFilter = ctx.addFilter("securityFilter", securityFilterDecorator);
securityFilter.addMappingForUrlPatterns(null, false, "/*");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package edu.internet2.middleware.grouper.authentication.plugin;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;

import javax.servlet.ServletContainerInitializer;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

public class GrouperAuthentication implements BundleActivator {
private Map<String, ServiceReference> referenceMap = new HashMap<>();
private Map<String, ServiceRegistration> registrationMap = new HashMap<>();

@Override
public void start(BundleContext context) throws Exception {
ExternalAuthenticationServletContainerInitializer externalAuthenticationServletContainerInitializer = new ExternalAuthenticationServletContainerInitializer(context);
ServiceRegistration easciRegistration = context.registerService(ServletContainerInitializer.class, externalAuthenticationServletContainerInitializer, new Hashtable<>());
registrationMap.put(ExternalAuthenticationServletContainerInitializer.class.getCanonicalName(), easciRegistration);
}

@Override
public void stop(BundleContext context) throws Exception {
for (ServiceRegistration registration : registrationMap.values()) {
registration.unregister();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package edu.internet2.middleware.grouper.authentication.plugin;

import edu.internet2.middleware.grouper.authentication.plugin.config.ClientProvider;
import edu.internet2.middleware.grouper.authentication.plugin.config.ClientProviders;
import edu.internet2.middleware.grouperClient.config.ConfigPropertiesCascadeBase;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.pac4j.core.client.Client;
import org.pac4j.core.client.Clients;
import org.pac4j.core.config.Config;
import org.pac4j.core.config.ConfigFactory;
import org.pac4j.core.matching.matcher.PathMatcher;

public class Pac4jConfigFactory implements ConfigFactory {
// private static final Logger LOGGER = Logger.getLogger(Pac4jConfigFactory.class);
private static final Log LOGGER;
static {
try {
BundleContext bundleContext = FrameworkUtil.getBundle(Pac4jConfigFactory.class).getBundleContext();
//TODO: figure out why this is weird
ServiceReference<LogFactory> logfactoryReference = (ServiceReference<LogFactory>) bundleContext.getAllServiceReferences("org.apache.commons.logging.LogFactory", null)[0];
LOGGER = bundleContext.getService(logfactoryReference).getInstance(ExternalAuthenticationServletContainerInitializer.class);
} catch (InvalidSyntaxException e) {
throw new RuntimeException(e);
}
}

@Override
public Config build(Object... parameters) {
try {
ConfigPropertiesCascadeBase grouperConfig = ConfigUtils.getBestGrouperConfiguration();

String provider;
if (grouperConfig.containsKey("external.authentication.mechanism")) {
LOGGER.warn("you're using the deprecated key `external.authentication.mechanism`; please update to `external.authentication.provider`");
provider = grouperConfig.propertyValueString("external.authentication.mechanism");
} else {
provider = grouperConfig.propertyValueString("external.authentication.provider");
}
Client client = getClient(provider);

String callbackUrl = grouperConfig.propertyValueString("external.authentication.grouperContextUrl")
+ grouperConfig.propertyValueString("external.authentication.callbackUrl", "/callback");
final Clients clients = new Clients(callbackUrl, client);

final Config config = new Config(clients);

PathMatcher pathMatcher = new PathMatcher();

for (String exclusion : grouperConfig.propertyValueString("external.authentication.exclusions", "/status").split(",")) {
pathMatcher.excludeBranch(StringUtils.trim(exclusion));
}

config.addMatcher("securityExclusions", pathMatcher);
return config;
} catch (IllegalAccessException|InstantiationException e) {
throw new RuntimeException("problem configuring pac4j", e);
}
}

private static Client getClient(String provider) throws IllegalAccessException, InstantiationException {
Class<? extends ClientProvider> providerClass;
//TODO: might be a better way of doing this
try {
providerClass = ClientProviders.fromString(provider).getProviderClass();
} catch (IllegalArgumentException e) {
try {
providerClass = (Class<? extends ClientProvider>) Class.forName(provider);
} catch (ClassNotFoundException classNotFoundException) {
throw new RuntimeException(classNotFoundException);
}
}
return providerClass.newInstance().getClient();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package edu.internet2.middleware.grouper.authentication.plugin.config;

import edu.internet2.middleware.grouper.authentication.plugin.ConfigUtils;
import org.pac4j.cas.client.CasClient;
import org.pac4j.cas.config.CasConfiguration;
import org.pac4j.core.client.Client;

public class CasClientProvider implements ClientProvider {
@Override
public boolean supports(String type) {
return "cas".equals(type);
}

@Override
public Client getClient() {
final CasConfiguration configuration = new CasConfiguration();

ConfigUtils.setProperties(configuration, "cas");
CasClient client = new CasClient(configuration);
//TODO: make configurable
client.setName("client");
return client;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package edu.internet2.middleware.grouper.authentication.plugin.config;

import org.pac4j.core.client.Client;

public interface ClientProvider {
boolean supports(String type);
Client getClient();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package edu.internet2.middleware.grouper.authentication.plugin.config;

import java.util.Locale;

public enum ClientProviders {
CAS (CasClientProvider.class),
OIDC (OidcClientProvider.class),
SAML (SAML2ClientProvider.class);

private final Class<? extends ClientProvider> providerClass;

ClientProviders(Class<? extends ClientProvider> clazz) {
this.providerClass = clazz;
}

public Class<? extends ClientProvider> getProviderClass() {
return this.providerClass;
}

public static ClientProviders fromString(String name) {
return ClientProviders.valueOf(name.toUpperCase(Locale.ENGLISH));
}
}
Loading

0 comments on commit 5e57087

Please sign in to comment.