-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
initial java code
- Loading branch information
Showing
19 changed files
with
691 additions
and
0 deletions.
There are no files selected for viewing
145 changes: 145 additions & 0 deletions
145
src/main/java/edu/internet2/middleware/grouper/authentication/plugin/ConfigUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
...ware/grouper/authentication/plugin/ExternalAuthenticationServletContainerInitializer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, "/*"); | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
...in/java/edu/internet2/middleware/grouper/authentication/plugin/GrouperAuthentication.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} | ||
} |
80 changes: 80 additions & 0 deletions
80
src/main/java/edu/internet2/middleware/grouper/authentication/plugin/Pac4jConfigFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
...java/edu/internet2/middleware/grouper/authentication/plugin/config/CasClientProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
...in/java/edu/internet2/middleware/grouper/authentication/plugin/config/ClientProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} |
23 changes: 23 additions & 0 deletions
23
...n/java/edu/internet2/middleware/grouper/authentication/plugin/config/ClientProviders.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)); | ||
} | ||
} |
Oops, something went wrong.