http:outbound-gateway to follow redirect - spring-integration

I need to request a JWT Token via an HTTP request in my Spring Integration application.
I've configured a plain http outbound gatway but the server replies with a 301 Moved Permanently;
It requires the client to follow a redirect (and apparently it works this way doing some tests with SOAP-UI);
How could I make the http-outbound-gateway to follow redirects?
Tried everything I could find, but nothing worked so far.
Thanks!

You need consider to configure your HTTP Outbound Gateway with a HttpComponentsClientHttpRequestFactory. This one is based on the Apache HTTP Client 4.x and its default behavior is a DefaultRedirectStrategy which does a redirect on GET and HEAD methods and when 302, 301 or 307 status is returned for the call.
If you need to redirect POST, consider to configure an underlying HttpClient with a LaxRedirectStrategy.
See more info here: Handling HttpClient Redirects
UPDATE
To configure a LaxRedirectStrategy for the HttpClient used in the HttpComponentsClientHttpRequestFactory you need something like this:
<beans:bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClients" factory-method="custom">
<beans:property name="redirectStrategy" value="#{new org.apache.http.impl.client.LaxRedirectStrategy()}"/>
</beans:bean>
<beans:bean id="clientHttpRequestFactory"
class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<beans:constructor-arg>
<beans:bean factory-bean="httpClientBuilder" factory-method="build"/>
</beans:constructor-arg>
</beans:bean>
It is kinda pitta to do all that stuff in XML, so consider to move your project to Java & annotation configuration.

Related

Picketlink on JBoss sends LogoutRequest to incorrect endpoint

I'm trying to secure an application using picketlink. I'm using JBoss 6.4.18.
The SSO operation works without any issues. The problem is with the SLO, basically, picketlink sends the LogoutRequest assertion to the wrong endpoint. The IdP metadata inside my war has these endpoints:
<md:ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://myidp.com/saml2/soap" index="0" isDefault="true"/>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://myidp.com/saml2/slo" ResponseLocation="https://myidp.com/saml2/slo_return"/>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://myidp.com/saml2/slo" ResponseLocation="https://myidp.com/saml2/slo_return"/>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://myidp.com/saml2/soap"/>
<md:ManageNameIDService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://myidp.com/saml2/rni" ResponseLocation="https://myidp.com/saml2/rni_return"/>
<md:ManageNameIDService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://myidp.com/saml2/rni" ResponseLocation="https://myidp.com/saml2/rni_return"/>
<md:ManageNameIDService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://myidp.com/saml2/soap"/>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://myidp.com/saml2/sso"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://myidp.com/saml2/sso"/>
<md:NameIDMappingService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://myidp.com/saml2/soap"/>
LogoutRequest assertion looks good to me, but, picketlink sends it to the /sso endpoint instead of using /slo (as indicated by the metadata). When the idp receives that LogoutRequest it doesn't even redirect the browser back to the SP application.
The assertion actually has the correct destination, but as I said, the browser sends to the /sso endpoint.
<samlp:LogoutRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
Destination="https://myidp.com/saml2/sso"
Is this a bug in picketlink?
I must say that I've configured it using other IdP servers where the endpoint is the same for both types of assertions, in such cases, the SLO worked perfectly.
I'd appreciate your help on this one.
Thank you.
In the end I couldn't fix this by configuration. One would expect picketlink to send the SLO assertions to the endpoint declared in the metadata file, but as I described in the question above it doesn't.
By checking the plugin code I saw that it can read a request parameter to decide what endpoint send the Logout Request assertion to.
So, when the SP requests a GLO I add another request parameter as follows:
/?GLO=true&picketlink.desired.idp="+encodedSLOEndpointURL
picketlink reads that parameter (picketlink.desired.idp) and sends the assertion to that endpoint on the IdP side.
P.S. I hope this is the last time I have to deal with such an old library like picketlink.

Shibboleth ACS URL mismatch with http and https

My ACS URL is being rewritten from https://foo.com/ to http://foo.com/ which is causing the below Exception.
Microsoft.IdentityServer.Service.Policy.PolicyServer.Engine.AssertionConsumerServiceUrlDoesNotMatchPolicyException: MSIS3200: No AssertionConsumerService is configured on the relying party trust 'foo-shibboleth-sp' that is a prefix match of the AssertionConsumerService URL 'http://foo/Shibboleth.sso/SAML2/POST' specified by the request.
The log message reflects that the auth request was sent as http as well:
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
AssertionConsumerServiceURL="http://foo/Shibboleth.sso/SAML2/POST"
Destination="https://bar/adfs/ls/"
ID="_12345ID" IssueInstant="2017-08-08T22:24:28Z"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Version="2.0"><saml:Issuerxmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">foo-shibboleth-sp</saml:Issuer><samlp:NameIDPolicy AllowCreate="1"/></samlp:AuthnRequest>
2017-08-08 22:24:28 DEBUG OpenSAML.MessageEncoder.SAML2Redirect [1]: message encoded, sending redirect to client
I have included my configuration below.
The SP metadata I've configured in my IDP has the correct URL with https, but is being changed to http somewhere downstream and can be seen in the Shibboleth logs for the samlp auth request.
If I switch handlerSSL to TRUE, the ACS URL in the samlp auth request shows https. However, when it's set to TRUE, anything at the path of /Shibboleth.sso/ such as /Status, or /SAML2/POST are 404ing.
I should also note that this is actually a site migration and this was all on windows in a datacenter now it's on Linux in AWS. There could be an issue with the Load Balancer where we terminate SSL, but haven't been able to debug that.
In the SP metadata that was provided to the IDP, I specify the https /SAML2/POST url. There is a bunch of config here, but I tried to highlight the relevant stuff.
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" ID="_97e389f1c212...." entityID="foo-shibboleth-sp">
...
<init:RequestInitiator xmlns:init="urn:oasis:names:tc:SAML:profiles:SSO:request-init" Binding="urn:oasis:names:tc:SAML:profiles:SSO:request-init" Location="https://foo/Shibboleth.sso/Login"/>
....
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://foo/Shibboleth.sso/SAML2/POST" index="10"/>
Then, in the shibboleth2.xml on my SP, I have the following application override config:
<ApplicationOverride id="lms" entityID="foo-shibboleth-sp"
homeURL="/path/to/sso/location">
<Sessions lifetime="28800" timeout="3600" checkAddress="false"
handlerURL="/Shibboleth.sso" handlerSSL="false"
exportLocation="https://foo/Shibboleth.sso/GetAssertion" exportACL="127.0.0.1"
idpHistory="false" idpHistoryDays="7">
<!-- Default example directs to a specific IdP's SSO service (favoring SAML 2 over Shib 1). -->
<SessionInitiator type="Chaining" Location="/Login" isDefault="true" id="Intranet"
relayState="cookie" entityID="http://bar/adfs/services/trust">
<SessionInitiator type="SAML2" acsIndex="1" template="bindingTemplate.html"/>
<SessionInitiator type="Shib1" acsIndex="5"/>
</SessionInitiator>
</Sessions>
<MetadataProvider type="XML" file="/etc/shibboleth/metadata-sp.xml"/>
<!-- Map to extract attributes from SAML assertions. -->
<AttributeExtractor type="XML" validate="true" path="/etc/shibboleth/attribute-map.xml"/>
</ApplicationOverride>
Finally, the only other piece that I have determined could be causing issues, is the IDP metadata here:
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" ID="_1234-..." entityID="http://bar/adfs/services/trust">
...
<AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://bar/adfs/ls/" index="0" isDefault="true" />
....
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://bar/adfs/ls/" />
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://bar/adfs/ls/" />
apache config also, though it seems pretty cookie-cutter
<Location />
ShibRequestSetting applicationId lms
</Location>
<Location /path/to/sso/location>
ShibRequestSetting applicationId lms
AuthType shibboleth
ShibRequestSetting requireSession 1
require valid-user
</Location>
The problem ended up being related to SSL Offload with the AWS Load Balancer. Because we were terminating at the ELB, we needed to set https:// on the ServerName directive in Apache config so that it would generate the https self-referential urls.
http://httpd.apache.org/docs/2.2/mod/core.html#servername

How do I get the request URL for message headers

I have an inbound gateway to process JSON payloads. Since we utilize the same backend service as our SOAP endpoints, I need to have an inbound gateway that maps to all paths. I can see the default HTTP headers come across the into the message, but I specifically need the request URL so I can parse it and route to the appropriate serve as needed.
My inbound-gateway:
<int-http:inbound-gateway id="JSONGateway"
path="*" request-channel="JSONRequestChannel" supported-methods="POST"
reply-timeout="5000"
header-mapper="headerMapper"
request-payload-type="java.lang.String" >
</int-http:inbound-gateway>
I tried adding a header-enricher like I do for SOAP, but the TransportContextListener is null.
<int:header-enricher input-channelJSONequestChannel"
output-channel="JSONRequestChannelWithHeaders">
<int:header name="service"
expression="T(org.springframework.ws.transport.context.TransportContextHolder).transportContext.connection.uri.toString().substring(T(org.springframework.ws.transport.context.TransportContextHolder).transportContext.connection.uri.toString().lastIndexOf('/')+1)" />
</int:header-enricher>
I need a way to get the URL of the request so I can parse out the service into the message headers for my downstream router.
/json/ContactService = "ContactService"
/json/ContactService/insert = "ContactService"
/json/ContactService/get/234 = "ContactService"
I also tried adding a header-mapper class, but still run into the same problem. How can I get a handle to the HTTPServletRequest in code? Once I get that I can get all the headers I need.
Well, you didn't check the message headers.
After converting ServletServerHttpRequest to the Message it gets these headers by default:
Message<?> message = messageBuilder
.setHeader(org.springframework.integration.http.HttpHeaders.REQUEST_URL,
request.getURI().toString())
.setHeader(org.springframework.integration.http.HttpHeaders.REQUEST_METHOD,
request.getMethod().toString())
.setHeader(org.springframework.integration.http.HttpHeaders.USER_PRINCIPAL,
servletRequest.getUserPrincipal())
.build();
So, http_requestUrl is for you to go ahead and parse it appropriately.

Setup a redirection in IIS with parameters carried over

If I have a website like the following:
https://xxx/section1/
https://xxx/section2/
https://xxx/section3/
But users may also access the URLs with parameters:
https://xxx/section1/&p=1494943
I'm going to create a seperate site in IIS6 which will redirect any HTTP requests to the HTTPS website:
request: http://xxx/
redirected to: https://xxx/
And in the same sense:
request: http://xxx/section2/&p=1474724
redirected to: https://xxx/section2/&p=1474724
My question is, how can I ensure they are redirected to the correct section and still carry over the parameters?
Thank you very much for your help.
If you set the $Q flag in the redirect URL, the request/query parameters should be included in the redirect from the original. If you don't want the question mark to be included in the redirect URl, then use $P instead.
examples:
using $Q:
Original URL: http://startingURL?param1=1&param2=2
Redirect URL: https://newURL$Q
Resulting URL: https://newURL?param1=1&param2=2
using $P:
Original URL: http://startingURL?param1=1&param2=2
Redirect URL: https://newURL$P
Resulting URL: https://newURLparam1=1&param2=2
For additional reading, take a look at the TechNet article: http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/41c238b2-1188-488f-bf2d-464383b1bb08.mspx?mfr=true
I had a similar problem when moving a DokuWiki instance from one server to another and then wanted to set up a HTTP redirect so it would redirect request from e.g.:
https://bananas.tycoon.ex/doku.php?id=knowledgebase:iis
...to:
https://oranges.tycoon.ex/doku.php?id=knowledgebase:iis
I tried a variety of things before I found a working solution for this. Here is the web.config configuration that finally achieved the desired result:
<configuration>
<system.webServer>
<httpRedirect enabled="true" destination="https://oranges.tycoon.ex$S$Q" exactDestination="true" />
</system.webServer>
</configuration>
The final important part was the [exactDestination="true"]. Without this, I was instead redirected to:
https://oranges.tycoon.ex/doku.php?id=knowledgebase:iis/doku.php
...which naturally landed me on a nonexisting page of the wiki thanks to the extra appended "/doku.php".

iisnode - IIS7.5: 405 Method not allowed when performing PUT request

I started to do some experimentation with iisnode and expressjs to create a REST like API with node.
So on the server.js I created something like
app.put("/test", function(req, res){
...
});
However, when I execute the PUT request I get a 405 Method not allowed from the IIS 7.5 installation.
Any idea on how to solve this?
BTW, I googled already and tried to add the PUT verbs here and there in the different Handler Mappings with no success...
I now finally found the solution to this problem namely the WebDavModule was blocking my PUT requests.
To resolve the issue:
Open your IIS Manager
Goto your application configuration and open "Modules"
Search WebDavModule and remove it (menu on the right)
It then worked for me.
Alternatively, in your application's web.config add
<system.webServer>
...
<modules>
<remove name="WebDAVModule"/>
</modules>
</system.webServer>
One reason may be that your web.config does not map the particular request you are making to the iisnode handler. In that case the request is picked up by the static request handler which does not support PUT methods and responds with a 405.
To fix this you need a iisnode handler registration like this in your web.config: https://github.com/tjanczuk/iisnode/blob/master/src/samples/helloworld/web.config#L7
In addition, if you plan to use URL that do not end with the name of your node.js file (like seems to be the case above), you will need to use a URL rewrite module to tell IIS exactly which requests should have their URLs rewritten to point to the URL of your node.js entry point. Read more at: http://tomasz.janczuk.org/2011/08/using-url-rewriting-with-nodejs.html

Resources