Oauth 1.0a consumer code equesting an access token twice - oauth

I've setup a consumer app, and most of the oauth workflow looks correct, but for some reason after the callback url is invoked by the provider, it tries to get an access token TWICE. The first time works
http://localhost:8080/app/ws/oauth/token
[OAuth oauth_consumer_key="itd79n64zlwv5hhv", oauth_nonce="cac26978-c36c-4a8b-8f3e-3e779ff927ab", oauth_signature="5c8BM9qQoijXC2f5IXpQGtSQsys%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1458938403", oauth_token="5451cf20-7eed-4797-819c-ee2316981654", oauth_verifier="c56de555-79df-455e-ab87-f5f11b953fef", oauth_version="1.0"]
response is a 200, payload includes oauth_token=a95d6305-4261-4c1d-a9b0-43411a0c2f2c&oauth_token_secret=573702d2-70ca-412c-84e5-868e9ee07169
but then, it calls the URL again.
http://localhost:8080/app/ws/oauth/token
[OAuth oauth_consumer_key="itd79n64zlwv5hhv", oauth_nonce="6c013ef9-2f3c-49dd-84fb-97db73b5fb39", oauth_signature="5RTQE5XtcqUwEFVvYQjExhH1eio%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1458938403", oauth_token="5451cf20-7eed-4797-819c-ee2316981654", oauth_verifier="c56de555-79df-455e-ab87-f5f11b953fef", oauth_version="1.0"
which causes an exception on the server since the request token has been removed and the access token has already been issued.
When stepping through the code, I can see that the OAuthConsumerContextFilter stores the access token fine after the first call.
Somehow the filter chain ends up bring it back to readResource in CoreOAuthConsumerSupport with the request token.
I built the consumer app using spring-boot.
from: applicationContext.xml
<bean id="oscarService" class="com.mdumontier.oscar.labline.service.OscarService">
<property name="oscarRestTemplate">
<bean class="org.springframework.security.oauth.consumer.client.OAuthRestTemplate">
<constructor-arg ref="oscar" />
</bean>
</property>
</bean>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="marissa" password="wombat" authorities="ROLE_USER" />
<security:user name="sam" password="kangaroo" authorities="ROLE_USER" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
<security:http auto-config='true' >
</security:http>
<oauth:consumer resource-details-service-ref="resourceDetails" oauth-failure-page="/oauth_error.jsp">
<oauth:url pattern="/oscar/**" resources="oscar"/>
</oauth:consumer>
<oauth:resource-details-service id="resourceDetails">
<oauth:resource id="oscar"
key="itd79n64zlwv5hhv"
secret="d3psvmrn8k1xws9x"
request-token-url="http://localhost:8080/app/ws/oauth/initiate"
user-authorization-url="http://localhost:8080/app/ws/oauth/authorize"
access-token-url="http://localhost:8080/app/ws/oauth/token"/>
</oauth:resource-details-service>

Spring Boot automatically registers any Beans which implement Filter in the main application filter chain. See: https://stackoverflow.com/a/28428154 for a bit more detail.
The oauth:consumer helper registers both OAuth filters as beans, and seems to not have been updated in a while. I couldn't even get the XML config to work properly under the latest Spring Boot. Anyway, this means that both will be run twice, and in the case of the OAuthConsumerContextFilter this is destructive since it will run outside the security sub-chain and fail every time.
To fix this you have two options.
One, hint to Spring Boot to avoid this behavior by providing a FilterRegistrationBean for each filter it's automatically picking up, like so:
#Bean
public FilterRegistrationBean registration(OAuthConsumerContextFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
}
Two, bypass the XML config entirely and use Java config. I've posted a complete working code sample of getting on OAuth 1 consumer in Spring Boot using Java config in this answer: https://stackoverflow.com/a/42143001/2848158
Within the Java config, you would have to either repeat the FilterRegistrationBean trick, or just not register those filters as beans in the first place but rather create and register instances directly with the Security filter chain.

Related

Mule 3.7 HTTP basic security filter error when calling local service

I am calling one mule flow from another using HTTP with basic authentication using the Spring Security Manager. I am using Mule 3.7 and configured everything according to the documentation at:
https://docs.mulesoft.com/mule-user-guide/v/3.7/configuring-the-spring-security-manager
<spring:beans>
<ss:authentication-manager alias="authenticationManager">
<ss:authentication-provider>
<ss:user-service id="userService">
<ss:user name="${security.user.id}" password="${security.user.password}" authorities="ROLE_ADMIN" />
</ss:user-service>
</ss:authentication-provider>
</ss:authentication-manager>
</spring:beans>
<mule-ss:security-manager>
<mule-ss:delegate-security-provider name="memory-dao" delegate-ref="authenticationManager" />
</mule-ss:security-manager>
<http:listener-config name="httpLocalListener" host="${local.host}" port="${local.port}"
basePath="${local.path}" doc:name="HTTP Local Listener" connectionIdleTimeout="${local.timeout}"/>
<http:request-config name="httpLocalRequest" doc:name="HTTP Local Configuration" responseTimeout="${local.timeout}"
basePath="${local.path}" host="${local.host}" port="${local.port}">
<http:basic-authentication username="${security.user.id}" password="${security.user.password}"/>
</http:request-config>
<flow name="ServiceFlow1" processingStrategy="synchronous">
<http:listener config-ref="httpLocalListener" path="/status/*" doc:name="HTTP" allowedMethods="GET"/>
<http:basic-security-filter realm="${security.filter.realm}"/>
<!-- Omitted code -->
<http:request config-ref="httpLocalRequest" path="/ping/txt?siteId=#[sessionVars['siteId']]" method="GET" doc:name="HTTP" parseResponse="false">
<http:success-status-code-validator values="0..599"/>
</http:request>
</flow>
<flow name="ServiceFlow2" processingStrategy="synchronous">
<http:listener config-ref="httpLocalListener" path="/ping/txt" doc:name="HTTP" allowedMethods="GET"/>
<http:basic-security-filter realm="${security.filter.realm}"/>
<!-- Omitted code -->
</flow>
I get the following error (I removed '//' from http links due to stackoverflow requirements):
ERROR 2016-08-19 10:28:09,539 [[Service].httpLocalListener.worker.02]
org.mule.exception.DefaultMessagingExceptionStrategy:
Message : Registered authentication is set to org.mule.transport.http.filters.HttpBasicAuthenticationFilter but there was no security context on the session. Authentication denied on endpoint http:0.0.0.0:8081/services/ping/txt. Message payload is of type: NullPayload
Type : org.mule.api.security.UnauthorisedException
Code : MULE_ERROR--2
JavaDoc : http:www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/security/UnauthorisedException.html
Payload : {NullPayload}
Exception stack is:
1. Registered authentication is set to org.mule.transport.http.filters.HttpBasicAuthenticationFilter but there was no security context on the session. Authentication denied on endpoint http:0.0.0.0:8081/services/ping/txt. Message payload is of type: NullPayload (org.mule.api.security.UnauthorisedException)
org.mule.transport.http.filters.HttpBasicAuthenticationFilter:156 (http:www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/security/UnauthorisedException.html)
Any help would be appreciated!
Thanks,
Dennis
I had the same kind of issue once, but that issue disappeared when I invoked the same URL from Postman where we hit the service along with credentials for basic authentication. The same doesn't work with a normal browser based test because when you invoke the service, it expects the credentials for the basic authentication and then given a pop-up for the same in next instance.
HTTPs basic auth using Postman Client
AM not sure whether this helps or not because my explanation is a bit immature, but might help you get a better idea on the implementation. only thing I can say is, it will throw an error but will work as desired.

Spring SAML configuration is breaking other http connections

I am using Spring SAML to implement single sign on in my application. Evreything is integrated and works properly from SSO perspective.
Another service of my application which also uses HTTP client post via Axis started failing with the following error
{http://xml.apache.org/axis/}stackTrace:javax.net.ssl.SSLPeerUnverifiedException: SSL peer failed hostname validation for name: null
I have looked into the answer provided the link
Spring Security SAML + HTTPS to another page and follow the same but to no avail.
Below is the configuration for TLSProtocolSocketFactory
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="org.apache.commons.httpclient.protocol.Protocol"/>
<property name="targetMethod" value="registerProtocol"/>
<property name="arguments">
<list>
<value>https</value>
<bean class="org.apache.commons.httpclient.protocol.Protocol">
<constructor-arg value="https"/>
<constructor-arg>
<bean class="org.springframework.security.saml.trust.httpclient.TLSProtocolSocketFactory">
<constructor-arg ref="keyManager"/>
<constructor-arg><null/></constructor-arg>
<constructor-arg value="allowAll"/>
</bean>
</constructor-arg>
<constructor-arg value="443"/>
</bean>
</list>
</property>
</bean>
I have imported the cert of the other service in samlKeystore.jks as well.
Any help in the issue will be apreciated
I think this may be what you're looking for: Source
You are using bean TLSProtocolConfigurer which changes trusted certificates and hostname verification of the HTTPS protocol in the HTTP Client. You can revert behaviour of the HTTP Client back to defaults by removing this bean. You will then need to make sure that certificates used by entities from which you load metadata (https://idp.ssocircle.com/idp-meta.xml) are trusted in your cacerts, or use an endpoints without https (http://idp.ssocircle.com/idp-meta.xml).
Alternatively, you can disable hostname verification by setting property sslHostnameVerification to allowAll on bean TLSProtocolConfigurer. You will also need to make sure that the HTTPS certificate of https://www.somepage.com (or its CA) is included in the samlKeystore.jks (see Spring SAML manual).
You can find more details on the TLSProtocolConfigurer bean in the Spring SAML manual, chapter HTTP-based metadata provider with SSL.
The issue is in checkNames() function of PKIXX509CredentialTrustEngine where we are checking the trustedNames collection only for null instead of "null or Empty".Even though we are passing the value for trustedNames as null in TLSProtocolSocketFactory's getPKIXResolver() method to create StaticPKIXValidationInformatonResolver, the constructor of this class reinitialized the trustedNames collection to an empty collection.Changing the line from if(trustedNames == null) to if(trustedNames == null || trustedNames.isEmpty()) fixed the problem for me.

Spring Security, programmatic login for json restful web service

I am using spring 4.2.1 with spring security 4.0.2
On login, I need to return a json object tree to the client, containing the cached data it requires for the session.
So I've added a the following method:
#RequestMapping(value = "/login", method = RequestMethod.POST)
public #ResponseBody ServerResponse<?> login(#RequestBody LoginRequest loginRequest, HttpServletRequest request, HttpServletResponse response) {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());
Authentication result = authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(result);
Object data = null; // Do stuff here
return new ServerResponse<>(data);
}
My spring security config:
<ss:http auto-config="false" use-expressions="true" entry-point-ref="authenticationEntryPoint">
<ss:anonymous enabled="false" />
<!-- this is enabled by default in spring 4 -->
<ss:csrf disabled="true" />
<ss:custom-filter position="FORM_LOGIN_FILTER" ref="myAuthFilter" />
<ss:session-management session-authentication-strategy-ref="sas" />
<ss:port-mappings>
<ss:port-mapping http="8080" https="8443" />
</ss:port-mappings>
<ss:intercept-url pattern="/app/logi**" access="permitAll()" />
<ss:intercept-url pattern="/app/logou**" access="permitAll()" />
<ss:intercept-url pattern="/app/**" access="hasAuthority('user')" />
<ss:intercept-url pattern="/www/**" access="hasAuthority('user')" />
</ss:http>
All the pages I find regarding a programmatic login confirm that what I am doing is fine.
However, when I try and call another web service method later, I get 403 as the client is not logged in.
I read some vague references to having to use a spring filter, but I am not sure how I would get the filter to return the json tree to the client after successful login.
Any suggestions or links to an example on how to do this would be much appreciated.
Thanks
Sooo it turns out the problem was that I was doing Cross Origin Resource Sharing and the browser was not sending the cookie across with the next request.
Basically I was calling the server from html on the file system (with origin file://)
I was handling options calls, but I was not sending back
Access-Control-Allow-Credentials true
headers in the responses and I had to configure angular to send the cookie by passing the flag
withCredentials: true
in the config object to $http.post

spring-messaging xml config with stomp and spring-sessions

I'm trying to set up WebSockets with spring-messaging using stomp, and using redis-backed sessions with spring-session. Our application context is wired via xml, and spring-session is working with the non-websocket portion of the application. The relevant config for websocket is as follows
<websocket:message-broker application-destination-prefix="/streaming" >
<websocket:stomp-endpoint path="/data">
<websocket:sockjs session-cookie-needed="false" />
</websocket:stomp-endpoint>
<websocket:stomp-broker-relay prefix="/topic" relay-host="${jms_hostname}" relay-port="${jms_stomp_port}" />
<websocket:client-inbound-channel>
<websocket:interceptors>
<ref bean="sessionRepoMessageInterceptor"/>
<ref bean="authenticationValidationInterceptor" />
<ref bean="selectorValidationInterceptor" />
<ref bean="selectorQuotingInterceptor" /> <!-- comes after we have validated the selector, we now shim it so JMS understands it -->
</websocket:interceptors>
</websocket:client-inbound-channel>
</websocket:message-broker>
I have defined what I think are the necessary beans for spring-session's integration with web sockets here:
<bean id="redisSessionBackedWebsocketHandler" class="org.springframework.session.web.socket.server.">
</bean>
<bean id="sessionRepoMessageInterceptor" class="org.springframework.session.web.socket.server.SessionRepositoryMessageInterceptor">
</bean>
<bean id="webSocketRegistryListener" class="org.springframework.session.web.socket.handler.WebSocketRegistryListener">
</bean>
but I'm not sure where I would wire them in to the web socket configuration, and have not been able to find any doc on how to do it this way.
Thoughts?
The Spring Session WebSocket contains the config just only for the Java & Annotation variant.
And according to the Spring Session Docs the AbstractSessionWebSocketMessageBrokerConfigurer does the stuff for seamless integration between Spring Session and Spring WebSockets. However there we can see some paragraph, what it does:
To hook in the Spring Session support, we need to ensure ...
To be honest it isn't so easy to configure that stuff from XML.
Feel free to follow with the issue: https://github.com/spring-projects/spring-session/issues/101

Spring social linkedin not sending "state" parameter with oAuth2

I am trying to implement Linkedin social login in a Spring Application; I am using the most recent release spring-social-linkedin-1.0.0.RC4 and spring-social-1.0.3.RELEASE.
I manage to get to the point where authorization link is sent to Linkedin:
https://www.linkedin.com/uas/oauth2/authorization?client_id=....&response_type=code&redirect_uri=....
but the request is sent without the mandatory "state" request parameter, so it always results in an error from Linkedin. I double checked that simply adding the missing parameter to te url by hand results in the correct login page from linkedin, so I know client id is right.
Here's the code I use to connect to Linkedin:
User principal = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
ConnectionRepository repository = usersConnectionRepository.createConnectionRepository(principal.getUsername());
Connection<LinkedIn> connection = repository.findPrimaryConnection(LinkedIn.class);
return connection.getApi();
And the configuration for connectionFactoryLocator, where placeholders are resolved correctly:
<bean id="connectionFactoryLocator"
class="org.springframework.social.connect.support.ConnectionFactoryRegistry">
<property name="connectionFactories">
<list>
<bean
class="org.springframework.social.linkedin.connect.LinkedInConnectionFactory">
<constructor-arg value="${linkedin.api.key}" />
<constructor-arg value="${linkedin.api.secret}" />
</bean>
</list>
</property>
</bean>
Everything else is configured by the book and it's pretty standard spring social + jdbc setup.
I think "state" and "scope" parameters should be configured in the same way as "api.key" and "api.secret" (which are correctly set in the request), but I can't find how.
Did someone manage to get this right?
I found out: the simplest way to do it is to use an Interceptor and add it to the ConnectController. You will be able to add any parameter you like there.
Or upgrade to spring social 1.1.0 which has automatic state parameter handling (it's currently at RC1 stage).

Resources