How do I configure IdP metadata with HTTP url that can fallback to local file? - spring-saml

Spring Security SAML documentation suggests that you can configure the metadata for an Identity Provider by providing its metadata url, and having it fallback to a downloaded copy on your local filesystem (in case of a network hiccup).
I want to use FileBackedHTTPMetadataProvider which appears to be a hybrid of HTTPMetadataProvider and FilesystemMetadataProvider, however there's no documentation for how to use it in your securityContext.xml
It has two constructors:
#DEPRECATED String metadataURL, int requestTimeout, String backupFilePath
Timer backgroundTaskTimer, HttpClient client, String metadataURL, String backupFilePath
The url, timeout, file looks easier to construct, I don't have a timer, or httpclient...
Here is my thought on how I would want to do this, but I don't know how to get my metadata file from the classpath... Maybe thats a different question.
<bean class="org.opensaml.saml2.metadata.provider.FileBackedHTTPMetadataProvider">
<constructor-arg value="https://adfs.example.com/FederationMetadata/2007-06/FederationMetadata.xml"/>
<constructor-arg><value type="int">15000</value></constructor-arg>
<constructor-arg>
<bean class="org.opensaml.util.resource.ClasspathResource">
<constructor-arg value="/metadata/Federation_idp.xml"/>
</bean>
</constructor-arg>
</bean>
That ClasspathResource bit doesn't compile/run. It wants a string.
<contructor-arg value="/home/user/adfsmetadata/Federation_idp.xml"/>

Since the constructor just needs a String, you just gotta make your arg of the right type. Like so:
<constructor-arg>
<value type="java.lang.String">/dir/dir/metadata/Federation_idp.xml</value>
</constructor-arg>
If the server doesn't blow up, but it's not picking up your file, you can see if Java is really grabbing path you think try FileMon (windows) or an alternative like fs_usage (OS X) with some grepping. :)

Related

ADFS integration using Spring SAML -SP metadata vs IDP metadata?

I implemented the Spring SAML sample application using ssocircle and it worked fine. Now I have been trying to implement it for the client's ADFS. Following is the configuration I think that is required, please correct me if I am wrong:
Change the first parameter below, to the federationMetadata.xml url provided by client
<bean class="org.opensaml.saml2.metadata.provider.HTTPMetadataProvider">
<constructor-arg>
<value type="java.lang.String">http://idp.ssocircle.com/idp-meta.xml</value>
</constructor-arg>
<constructor-arg>
<value type="int">5000</value>
</constructor-arg>
<property name="parserPool" ref="parserPool"/>
</bean>
Replace the entity id of SP metadata below:
<bean class="org.springframework.security.saml.metadata.MetadataGenerator">
<property name="entityId" value="replaceWithUniqueIdentifier"/>
<property name="extendedMetadata">
<bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
<property name="signMetadata" value="false"/>
<property name="idpDiscoveryEnabled" value="true"/>
</bean>
</property>
</bean>
I haven't been able to figure out the following:
All I have received is a url to adfs/../federationMetadata.xml, who is supposed to create the SP metadata?
Am I supposed to create SP metadata and provide to the client, to add it in adfs? Because, that's what I did using sample application. I added the generated metadata to ssocircle
Is my understanding, that point 1 would be adfs url, and point 2 will be SP entity id, correct?
I would be grateful if you could clarify the above to me, also if possible, point me to straightforward tutorial that helps in integrating SAML with Spring security enabled application as I haven't been able to find the same.
Many thanks
To make SAML between SP and IdP (ADFS) work, you have to mutually exchange metadata.
The ADFS metadata are available on the URL https://adfs-host/FederationMetadata/2007-06/FederationMetadata.xml and you can register them in your SP either with HTTPMetadataProvider, or download them and read them from classpath, or file system with ResourceBackedMetadataProvider.
For SP metadata, you have to configure MetadataGenerator (as you have it in your question) and then expose it via FilterChainProxy. Here is a Java configuration (it's equivalent for XML):
#Bean
public FilterChainProxy samlFilter() throws Exception {
List<SecurityFilterChain> chains = new ArrayList<SecurityFilterChain>();
chains.add(new DefaultSecurityFilterChain(
new AntPathRequestMatcher("/saml/metadata/**"), metadataDisplayFilter()));
return new FilterChainProxy(chains);
}
Than, you can access SP metadata on the URL https://sp-host/saml/metadata and register them on ADFS as a Relying Party Trust. Again, you can do this either via URL, or import data from the (downloaded) file.
Basically, you should be fine if you follow Spring Security SAML Reference Documentation which uses XML configuration. In case, you'll need to switch to Java configuration, you can find handy either referenced vdenotaris/spring-boot-security-saml-sample, or my working prototype sw-samuraj/blog-spring-security.

Spring web flow dynamic url

I'm learning to use Spring Webflow. I've already have a working flow, where i created an old school installer where a user creates a configuration object. This is working as intended. Now, what i want to do is to make possible to edit a configuration object. For this i would need to pass this flow the selected configuration object. I thought the best way to do is to pass an id to the webflow and with a help of a service set it as a flow variable. My question is how can i create this url mapping.
This is the current url mapping for this flow:
<bean id="flowMappings" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>/configuration=configController</value>
</property>
</bean>
is it possible to do something like this:
<bean id="flowMappings" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>/{id}/configuration=configController</value>
</property>
</bean>
Any help is greatly appreciated.
Okay i have the solution.
I wrote it here in case someone has a similar problem in the future.
So i did not need any of the above configuration, since in the flow config xml it is possible to define an input. So example you want to query a configurationId then you can do by the following:
Lets assume that you have the following flow url: http://localhost/flow.
Then you can pass a parameter to the flow.xml like this: http://localhost/flow?configurationId=1.
To pass it you have to define an input in the flow configuration like this: <input name="configurationId"/>.
And there is your id you can create a service for this to return a concrete object.

Spring Security Twitter Access Token

I'm trying to get the ability to write to someone's Twitter account through Java and Spring Social.
Whenever I request write access through my application on twitter, I get the following exception:
org.springframework.social.NotAuthorizedException: Invalid or expired token
org.springframework.social.twitter.api.impl.TwitterErrorHandler.handleClientErrors(TwitterErrorHandler.java:104)
org.springframework.social.twitter.api.impl.TwitterErrorHandler.handleError(TwitterErrorHandler.java:58)
org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:537)
However, when I turn off access, I don't get this exception, but I (obviously) lose the ability to write. From all the research I have done, I have yet to be able to find anything about spring social except that I need an access token. I cannot find Spring Social documentation that tells me where to get that.
Anyway, this is in my controller:
#Autowired
ConnectionRepository connectionRepository
private Twitter getTwitter() {
connectionRepository.findPrimaryConnection(Twitter.class).api
}
#RequestMapping(value = "/connect/twitter/connect/twitter")
String loggedIn(Model model) {
if (twitter?.authorized) {
model.addAttribute("screenName", twitter.userOperations().screenName)
twitter.timelineOperations().updateStatus("Welcome to Miami #helloWorld")
HOME
}
else {
"redirect:/twitter"
}
}
My ConnectionRepository implementation is a basic one for MongoDB. I don't think it is the issue, but if it is it is nearly identical to:
https://github.com/CarloMicieli/spring-social-mongo/blob/master/src/main/java/org/springframework/social/connect/mongo/MongoConnectionRepository.java
Here is my dispatch xml:
<bean class="org.springframework.social.connect.web.ConnectController">
<property name="applicationUrl" value="http://localhost:8081/MinnesotaCows/" />
</bean>
<bean class="org.springframework.social.connect.web.ProviderSignInController">
<property name="applicationUrl" value="http://localhost:8081/MinnesotaCows/" />
<property name="signUpUrl" value="/register" />
</bean>
<bean id="twitterConnectionFactory"
class="org.springframework.social.twitter.connect.TwitterConnectionFactory">
<constructor-arg value="bUC8VEWgkfkeTXuTBuxCg" />
<constructor-arg value="5I1CNYKBCkNbsbgL2JfTNdSnSA9JVY4KHI4myxV7k4" />
</bean>
<bean id="connectionFactoryLocator"
class="org.springframework.social.connect.support.ConnectionFactoryRegistry">
<property name="connectionFactories">
<list>
<ref bean="twitterConnectionFactory" />
</list>
</property>
</bean>
<bean id="textEncryptor" class="org.springframework.security.crypto.encrypt.Encryptors"
factory-method="noOpText" />
Note: I'm running at localhost. Could the problem be that? Since there is no callback? Also, I'm not using the signUpUrl in the ProviderSignInController for anything. I'm not quite sure what that is for either.
Anyone have any ideas on what I might be doing wrong - or how I can exactly get the access token through the API?
Thanks for your time!
I haven't tested CarloMicieli's mongo based connection repositories, but looking the code I can see that primary connection is the first connection created. This is the same behavior that the built in jdbc based repository in Spring Social has. But I think it's wrong, primary connection should be always the last issued connection/login to the provider (the connection with rank 1 can be expired even though there are newer connections).
You could try to empty the connections collection in your mongo db and test if your code works after that. If the token works then, it is the issue that I described.
I have created my own mongo based social repositories that rank the connections by timestamp and order them so that the last issued connection is the primary one. That way you can issue multiple logins and the last login will be the primary connection.
See reference from github: https://github.com/trautonen/spring-social-mongodb/tree/master/src/main/java/org/eluder/spring/social/mongodb
You also defined ConnectController which map the social provider connection paths. You can initialize login flow by doing POST request to /connect/twitter and if completed without problems should result a working connection in your connections collection in mongodb.
See full reference here: http://docs.spring.io/spring-social/docs/1.1.0.RELEASE/reference/htmlsingle/#creating-connections-with-connectcontroller

How to obtain a current user locale from Spring without passing it as a parameter to functions?

I am using Spring 3.1 and want to find the locale active for the current user is there a way to grab the locale directly without being forced to pass it from the controller to the service layer ... etc.
does spring store the locale in a thread local storage where it can be grabbed by calling some static method?
I was also looking for how to access the locale without passing the Locale around, but I'm still pretty new to Spring and found most solutions to be confusing. It turns out, though, that Spring MVC does store the locale in thread local storage. It can be accessed by:
Locale locale = LocaleContextHolder.getLocale();
The last approach [...] is based on a thread local in order to provide the current locale in any entity of your architecture. [...] You must be aware that the content of the LocaleContextHolder corresponds by default to the locale specified within the Web request.
From: Configuring locale switching with Spring MVC 3. (That post also offers alternative configurations/methods for getting the locale, which might be useful for anyone looking to do this).
You can also view the LocaleContextHolder docs from Spring here.
It depends on where you have configured to store the locale, in session or in cookie?
In my application I have configured to store the user locale in its session with below mentioned configuration.
<mvc:interceptors>
<ref bean="localeChangeInterceptor"/>
</mvc:interceptors>
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang"/>
</bean>
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
<property name="defaultLocale" value="en"/>
</bean>
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>/WEB-INF/i18n/labels</value>
<value>/WEB-INF/i18n/messages</value>
<value>/WEB-INF/i18n/include</value>
</list>
</property>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
If you have done somthing like this then you can easily retrieve the locale parameter from the session.
Hope this helps you.
Cheers.
We had the same need, so came up with putting Locale into ThreadLocal context. We already had an object (some user information) stored in ThreadLocal context, so just appended it (looks like a hack, but the quickest solution we found).

Good example of Spring Configuration using java.util.prefs or Commons Configuration

One application I'm working on has several URLs and other information that is instance specific. The first pass uses a typical Spring PropertyPlaceholderConfigurer with a properties file:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:application.properties"/>
</bean>
The main issue with this is of course the property file is an artifact that must be checked in, and for starting a new instance would require updating that artifact. For a streamline deployment, I would like to have the ApplicationContext bootstrap itself based on database table(s). I have seen solutions like this forum post, does anyone here know of better tools or is this defacto approach to this problem? I would also like to be able to update/reload the settings at runtime using JMX or other facilities, but having to restart the app after changes to the database would still be a better solution to the current one.
The way we did it was to put some configuration information in the environment and then pull the relevant info from there.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="searchSystemEnvironment" value="true" />
</bean>
If configuration changes then the app will need to be restarted. Can also put all the different configurations into the environment and nest the variables like the following:
<bean id="db" class="org.DataSource"
p:databaseServer="${${MODE}_DBSERVER}"
p:databaseName="${${MODE}_DBNAME}" />
where $MODE = dev, qa, etc.

Resources