Shiro with SAML2 in Karaf with JAX-RS (Jersey) - jersey

I am creating an application that runs in Karaf as OSGi container, and uses the OSGi HTTP Service and Jersey for exposing REST APIs. I need to add SAML2 authentication and permissions-based authorization. I would like to use the annotation based approach in Shiro for this, as spring seems to be moving away from OSGi. My questions:
Is Shiro with SAML jars a good fit in OSGi environments?
I want to use WSO2 as the identity provider. Are there any caveats of Shiro and WSO2 working together?
For using annotations, the Shiro docs indicate I need to put AspectJ/Spring/Guice jars - Is this still valid in OSGi environments? I would prefer Guice for all my DI needs.
Would be great to have some insights from Shiro users.
UPDATE
I'm using this project: osgi-jax-rs-connector. So, I use Guice-Peaberry to register OSGi services with the interfaces annotated with #Path or #Provider, and the tool takes care of converting them into a REST resource. (Similar to pax-whiteboard?). I was planning to similarly expose my filters as OSGi services, and then dynamically add them along with the resources.
I have had headaches with AspectJ in OSGi in a previous project where I had to switch to vanilla Equinox from Karaf because the equinox weaving hook was not agreeing with Karaf (stack traces from Aries were seen, among other things). So, would doing something like shiro-jersey be better?

I'm sure it is doable, though I already see some restrictions/issues poping up.
for
1) haven't tried it, though you need to make sure that you tell the pax-web and jetty about it, it'll require adding this to the jetty.xml and it might even need to add a fragment bundle to pax-web-jetty so the desired class can be loaded. This will most likely be your first classnotfound issue.
2) don't know of WSO2 so no idea
3) if you want to use annotations, be careful. For Guice you'll mostlikely will need to use Peaberry since afaik Guice isn't "OSGi-fied" yet. Using AspectJ isn't really a good idea in a OSGi environment due to the classloader restrictions. If you have a compile-time weaving it should be fine, but run-time weaving will be a challange.
UPDATE:
Completely forgot about it, but there is a Pax Shiro Project available, maybe this can be a good starting point to get your setup in a correct lineup.

In the interest of readers, I'm sharing the solution I arrived at after some research of existing tools. First, the easy part: Using Shiro annotations in an OSGi environment. I ended up writing the below class since most Shiro-Jersey adapters shared by developers is based on Jersey 1.x.
#Provider
public class ShiroAnnotationResourceFilter implements ContainerRequestFilter {
private static final Map, AuthorizingAnnotationHandler> ANNOTATION_MAP = new HashMap, AuthorizingAnnotationHandler>();
#Context
private ResourceInfo resourceInfo;
public ShiroAnnotationResourceFilter() {
ANNOTATION_MAP.put(RequiresPermissions.class,
new PermissionAnnotationHandler());
ANNOTATION_MAP.put(RequiresRoles.class, new RoleAnnotationHandler());
ANNOTATION_MAP.put(RequiresUser.class, new UserAnnotationHandler());
ANNOTATION_MAP.put(RequiresGuest.class, new GuestAnnotationHandler());
ANNOTATION_MAP.put(RequiresAuthentication.class,
new AuthenticatedAnnotationHandler());
}
public void filter(ContainerRequestContext context) throws IOException {
Class resourceClass = resourceInfo.getResourceClass();
if (resourceClass != null) {
Annotation annotation = fetchAnnotation(resourceClass
.getAnnotations());
if (annotation != null) {
ANNOTATION_MAP.get(annotation.annotationType())
.assertAuthorized(annotation);
}
}
Method method = resourceInfo.getResourceMethod();
if (method != null) {
Annotation annotation = fetchAnnotation(method.getAnnotations());
if (annotation != null) {
ANNOTATION_MAP.get(annotation.annotationType())
.assertAuthorized(annotation);
}
}
}
private static Annotation fetchAnnotation(Annotation[] annotations) {
for (Annotation annotation : annotations) {
if (ANNOTATION_MAP.keySet().contains(annotation.annotationType())) {
return annotation;
}
}
return null;
}
}
The complete project is here.
The above took care of Part 3 of my question.
For Shiro with SAML, I am using the Servicemix wrapped openSAML jar, and it seems to be working okay till now. I did however had to write a bit of code to make Shiro work with SAML2. It's almost on the same lines as shiro-cas, but is a bit more generic to be used with other IdPs. The code is kind of big so sharing a link to the project instead of copying classes to SO. It can be found here.
Now that I have some abstraction between my code and my IdP, WSO2 integration looks a bit simpler.
P.S. Thanks Achim for your comments and suggestions.

Related

Configuration Bean in Quarkus

This is regarding CDI spec of quarkus. Would want to understand is there a configuration bean for quarkus? How does one do any sort of configuration in quarkus?
If I get it right the original question is about #Configuration classes that can contain #Bean definitions. If so then CDI producer methods and fields annotated with #javax.enterprise.inject.Produces are the corresponding alternative.
Application configuration is a completely different question though and Jay is right that the Quarkus configuration reference is the ultimate source of information ;-).
First of all reading how cdi spec of quarkus differs from spring is important.
Please refer this guide:
https://quarkus.io/guides/cdi-reference
The learnings from this guide is there is #Produces which is an alternative to #Configuration bean in Quarkus.
Let us take an example for libs that might require a configuration through code. Example: Microsoft Azure IOT Service Client.
public class IotHubConfiguration {
#ConfigProperty(name="iothub.device.connection.string")
String connectionString;
private static final Logger LOG = Logger.getLogger(IotHubConfiguration.class);
#Produces
public ServiceClient getIot() throws URISyntaxException, IOException {
LOG.info("Inside Service Client bean");
if(connectionString==null) {
LOG.info("Connection String is null");
throw new RuntimeException("IOT CONNECTION STRING IS NULL");
}
ServiceClient serviceClient = new ServiceClient(connectionString, IotHubServiceClientProtocol.AMQPS);
serviceClient.open();
LOG.info("opened Service Client Successfully");
return serviceClient;
}
For all libs vertically intergrated with quarkus application.properties can be used and then you will get a driver obj for that broker/dbs available directly through #Inject in your #applicationScoped/#Singleton bean So, Why is that?
To Simplify and Unify Configuration
To Make Sure no code is required for configuring anything i.e. database config, broker config , quarkus config etc.
This drastically reduces the amount of code written for configuring and also Junits needed to cover that code.
Let us take an example where kafka producer configuration needs to be added: in application.properties
kafka.bootstrap.servers=${KAFKA_BROKER_URL:localhost:9092}
mp.messaging.outgoing.incoming_kafka_topic_test.topic=${KAFKA_INPUT_TOPIC_FOR_IOT_HUB:input_topic1}
mp.messaging.outgoing.incoming_kafka_topic_test.connector=smallrye-kafka
mp.messaging.outgoing.incoming_kafka_topic_test.value.deserializer=org.apache.kafka.common.serialization.StringDeserializer
mp.messaging.outgoing.incoming_kafka_topic_test.key.deserializer=org.apache.kafka.common.serialization.StringDeserializer
mp.messaging.outgoing.incoming_kafka_topic_test.health-readiness-enabled=true
For full blown project reference: https://github.com/JayGhiya/QuarkusExperiments/tree/initial_version_v1/KafkaProducerQuarkus
Quarkus References for Config:
https://quarkus.io/guides/config-reference
Example for reactive sql config: https://quarkus.io/guides/reactive-sql-clients
Now let us talk about a bonus feature that quarkus provides which improves developer experience by atleast an order of magnitude that is profile driven development and testing.
Quarkus provides three profiles:
dev - Activated when in development mode (i.e. quarkus:dev)
test - Activated when running tests
prod - The default profile when not running in development or test
mode
Let us just say that in the given example you wanted to have different topics for development and different topics for production. Let us achieve that!
%dev.mp.messaging.outgoing.incoming_kafka_topic_test.topic=${KAFKA_INPUT_TOPIC_FOR_IOT_HUB:input_topic1}
%prod.mp.messaging.outgoing.incoming_kafka_topic_test.topic=${KAFKA_INPUT_TOPIC_FOR_IOT_HUB:prod_topic}
This is how simple it is. This is extremely useful in cases where your deployments run with ssl enabled brokers/dbs etc and for dev purposes you have unsecure local brokers/dbs. This is a game changer.

Vulnerability warning with XStreamMarshaller

When using a XStreamMarshaller with spring batch, I get the following message:
Security framework of XStream not initialized, XStream is probably vulnerable.
First try: According to the documentation, I've tried to reset all permissions, but I still have the same message. Besides, I have no security error when parsing XML files... So I think that this code just doen't work. Here's a sample of code:
XStreamMarshaller marshaller = new XStreamMarshaller();
marshaller.getXStream().addPermission(NoTypePermission.NONE);
Second try: I have also tried with the setSupportedClasses method, but it doesn't work either (I still get the vulnerability message and not supported classes are still unmarshelled correctly):
XStreamMarshaller marshaller = new XStreamMarshaller();
marshaller.setSupportedClasses(FooBar.class);
How can I set security permissions with XStreamMarshaller?
Note: according to this thread, the Security Framework was introduced with 1.4.7 and it is still not mandatory.... But it will be mandatory for XStream 1.5.0!
Version of XStream used: 1.4.10
Version of Spring Batch used: 4.0.1
For information, I'm using Spring Boot (but I'm not sure it's relevant here)
Solution for the 'First Try':
The reason why it didn't work is that XStreamMarshaller instantiates a xstream object with afterPropertiesSet without checking if one have already been created, so we can't use getXStream() in a #Bean method. To make this work, we can for example set security config while injecting the marshaller in another bean:
#Configuration
public class JobSecurityConfig {
public JobSecurityConfig(XStreamMarshaller marshaller) {
XStream xstream = marshaller.getXStream();
XStream.setupDefaultSecurity(xstream);
xstream.allowTypes(new Class[]{Bar.class});
}
}
Another solution: extend XSreamMarshaller
You can also extend XStreamMarshaller and override only the customizeXStream() method to set security configuration.
#Override
protected void customizeXStream(XStream xstream) {
XStream.setupDefaultSecurity(xstream);
xstream.allowTypes(new Class[]{Bar.class});
}
Why the 'Second Try' doesn't work:
setSupportedClasses is only used on marshalling!!.. StaxEventItemReader doesn't care about supported classes!
Xstream website have provided details about the Security Framework Security Framework.
below method are provided to set Security permissions
XStream.addPermission(TypePermission);
XStream.allowTypes(Class[]);
XStream.allowTypes(String[]);
XStream.allowTypesByRegExp(String[]);
XStream.allowTypesByRegExp(Pattern[]);
XStream.allowTypesByWildcard(String[]);
XStream.allowTypeHierary(Class);
XStream.denyPermission(TypePermission);
XStream.denyTypes(Class[]);
XStream.denyTypes(String[]);
XStream.denyTypesByRegExp(String[]);
XStream.denyTypesByRegExp(Pattern[]);
XStream.denyTypesByWildcard(String[]);
XStream.denyTypeHierary(Class);
You can also refer this Tutorial
I hope this helps
From the official spring docs:
By default, XStream allows for arbitrary classes to be unmarshalled,
which can lead to unsafe Java serialization effects. As such, it is
not recommended to use the XStreamMarshaller to unmarshal XML from
external sources (i.e. the Web), as this can result in security
vulnerabilities.
You're using Spring's abstraction XStreamMarshaller to interface with the XStream library. By default the library can marshall/unmarshall arbitrary classes (including from external web source).
If you are not doing that (working with classes from external web sources) you can simply ignore the message.
If you want to remove the message follow what's recommended in Spring's official doc (linked above) and XStream website (security config example).
It boils down to setting up supported classes to make sure only the registered classes are eligible for unmarshalling.
This property is empty by default, which means - support all classes - hence the warning message you're getting.

Implement multi-tenanted application with Keycloak and springboot

When we use 'KeycloakSpringBootConfigResolver' for reading the keycloak configuration from Spring Boot properties file instead of keycloak.json.
Now there are guidelines to implement a multi-tenant application using keycloak by overriding 'KeycloakConfigResolver' as specified in http://www.keycloak.org/docs/2.3/securing_apps_guide/topics/oidc/java/multi-tenancy.html.
The steps defined here can only be used with keycloak.json.
How can we adapt this to a Spring Boot application such that keycloak properties are read from the Spring Boot properties file and multi-tenancy is achieved.
You can access the keycloak config you secified in your application.yaml (or application.properties) if you inject org.keycloak.representations.adapters.config.AdapterConfig into your component.
#Component
public class MyKeycloakConfigResolver implements KeycloakConfigResolver {
private final AdapterConfig keycloakConfig;
public MyKeycloakConfigResolver(org.keycloak.representations.adapters.config.AdapterConfig keycloakConfig) {
this.keycloakConfig = keycloakConfig;
}
#Override
public KeycloakDeployment resolve(OIDCHttpFacade.Request request) {
// make a defensive copy before changing the config
AdapterConfig currentConfig = new AdapterConfig();
BeanUtils.copyProperties(keycloakConfig, currentConfig);
// changes stuff here for example compute the realm
return KeycloakDeploymentBuilder.build(currentConfig);
}
}
After several trials, the only feasible option for spring boot is to have
Multiple instances of the spring boot application running with different spring 'profiles'.
Each application instance can have its own keycloak properties (as it is under different profiles) including the realm.
The challenge is to have an upgrade path for all instances for version upgrades/bug fixes, but I guess there are multiple strategies already implemented (not part of this discussion)
there is a ticket regarding this problem: https://issues.jboss.org/browse/KEYCLOAK-4139?_sscc=t
Comments for that ticket also talk about possible workarounds intervening in servlet setup of the service used (Tomcat/Undertow/Jetty), which you could try.
Note that the documentation you linked in your first comment is super outdated!

ManagedServiceFactory using Blueprint

The registration of a ManagedServiceFactory follows can be done as :-
private ServiceRegistration factoryService;
public void start(BundleContext context) {
Dictionary props = new Hashtable();
props.put("service.pid", "test.smssenderfactory");
factoryService = context.registerService(ManagedServiceFactory.class.getName(),
new SmsSenderFactory(), props);
}
How can one do this in a blueprint(Sample example would be highly useful) ?
Apache aries has support for Managed services. You can find examples in the integration tests of Apache Aries blueprint at https://svn.apache.org/repos/asf/aries/trunk/blueprint/blueprint-itests/src/test/resources/ManagedServiceFactoryTest.xml. In this case can change the code of your SMSSenderFactory not to implement ManagedServiceFactory directly as blueprint does it for you.
You can also embed your code (that you gave as a sample in your question) into the init-method of your bean if that was your question. In that case the ManagedServiceFactory should be unregistered in the destroy method of the bean.
Third option is to leave blueprint out of the game. You already have a ManagedServiceFactory implementation, why don't you simply register it in the Activator of the Bundle?
Fourth option is to use Declarative Services with one of the annotation set. In that case Metatype information will be also generated and you can configure your SMSSender via the webconsole.
I suggest you to use the last option.

Unit testing with Spring and the Jersey Test Framework

I'm writing some JUnit-based integration tests for a RESTful web service using JerseyTest. The JAX-RS resource classes use Spring and I'm currently wiring everything together with a test case like the following code example:
public class HelloResourceTest extends JerseyTest
{
#Override
protected AppDescriptor configure()
{
return new WebAppDescriptor.Builder("com.helloworld")
.contextParam( "contextConfigLocation", "classpath:helloContext.xml")
.servletClass(SpringServlet.class)
.contextListenerClass(ContextLoaderListener.class)
.requestListenerClass(RequestContextListener.class)
.build();
}
#Test
public void test()
{
// test goes here
}
}
This works for wiring the servlet, however, I'd like to be able to share the same context in my test case so that my tests can have access to mock objects, DAOs, etc., which seems to call for SpringJUnit4ClassRunner. Unfortunately, SpringJUnit4ClassRunner creates a separate, parallel application context.
So, anyone know how can I create an application context that is shared between the SpringServlet and my test case?
Thanks!
Override JerseyTest.configure like so:
#Override
protected Application configure() {
ResourceConfig rc = new JerseyConfig();
rc.register(SpringLifecycleListener.class);
rc.register(RequestContextFilter.class);
rc.property("contextConfigLocation", "classpath:helloContext.xml");
return rc;
}
For me the SpringServlet was not required, but if you need that you may be able to call rc.register for that too.
I found a couple of ways to resolve this problem.
First up, over at the geek#riffpie blog there is an excellent description of this problem along with an elegant extension of JerseyTest to solve it:
Unit-testing RESTful Jersey services glued together with Spring
Unfortunately, I'm using a newer version of Spring and/or Jersey (forget which) and couldn't quite get it to work.
In my case, I ended up avoiding the problem by dropping the Jersey Test Framework and using embedded Jetty along with the Jersey Client. This actually made better sense in my situation anyway since I was already using embedded Jetty in my application. yves amsellem has a nice example of unit testing with the Jersey Client and embedded Jetty. For Spring integration, I used a variation of Trimbo's Jersey Tests with Embedded Jetty and Spring

Resources