I am implementing SAML2.0 ServiceProvider in java using spring-security-saml-sample code. After successful login response gets redirect to root path(welcome file) of application.How to redirect it to any controller ?
Thanks,
Tejas
You can customize URL to which user gets redirected after successful authentication by changing bean successRedirectHandler, for example to:
<bean id="successRedirectHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/myControllerURL"/>
</bean>
If you're looking for the general way to maintain state through the login process, SAML2 is expected to preserve the RelayState variable (pass it alongside the SAMLRequest). Put whatever you'd like in it. I like base64'd json.
Related
I want a link on my login page that says "Log in with [identity provider]". For ssocircle, apparently the login link is
https://idp.ssocircle.com/sso/idpssoinit?metaAlias=%2Fpublicidp
But this link isn't located anywhere in the XML used to configure it. The IdP XML contains the following:
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://idp.ssocircle.com:443/sso/SSORedirect/metaAlias/publicidp"/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://idp.ssocircle.com:443/sso/SSOPOST/metaAlias/publicidp"/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://idp.ssocircle.com:443/sso/SSOSoap/metaAlias/publicidp"/>
Is it not possible to build the URL from these? Do I need to add a configuration for every IdP that includes asking for the login URL as well as the XML?
Unfortunately the URL that you call on the IDP is out of scope for SAML.
SAML only specify that it is possible for the IDP to start the authentication itself, not what triggers it to start. This is why it is not present in metadata
For the use case you describe you should use Service Provider initiated SSO. In that case the URL that will be used to send the AuthnRequest to is defined in the metadata XML that you mentioned.
But you end up with a logic in your own application which must generate the correct AuthnRequest. But that URL is under your control ...
Image from the spec describes the SP initiated flow:
I wish to confirm that RelayState is required for a valid signed SAML logout request.
We have federated Microsoft's ADFS 2012 R2 with Oracle's Identity Federation where ADFS is the SP and OIF is the IdP. As a basis, we followed Integrating ADFS 2.0/3.0 SP with OIF IdP.
Everything works, except logout. We have another SP doing a logout and working with OIF. One difference we've found is that ADFS is not sending a RelayState parameter with its signed logout request, but the other SP is. I've been using SAMLTool's Validate Logout Req, where I input the following:
SAML Logout Request
EntityId of the source
Target URL, Destination of the Logout Request
SigAlg
Signature of the SAML Logout Request
X.509 cert of the source (to check Signature)
Ignore timing issues: checked
That then gives me the error:
In order to check Signature you must provide the RelayState parameter and the X.509 cert
If I input RelayState along with my other values in SAMLTool's Validate Logout Req then it reports back that my signed logout request is valid.
In the case of ADFS, because it does not have a RelayState parameter, I cannnot get SAMLTool's Validate Logout Req to say that a logout from ADFS is valid.
All that said, I cannot find anywhere in the SAML spec that says RelayState is required for a signed logout request. Can anyone confirm that it is required and back it up with documentation?
The LogoutRequest message would not have a reference to the RelayState parameter (as the other post suggests) but it is part of the so-called binding that is used to convey messages between SAML parties. Assuming that the Logout uses the HTTP-Redirect, HTTP-POST or Artifact binding, the spec allows for the sender to include a RelayState parameter and the receiver must then return that same RelayState parameter as a part of the response (as a way for the sender to keep state).
See section 3.4.3 RelayState of the SAML bindings document: https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf for the HTTP-Redirect binding:
3.4.3 RelayState
RelayState data MAY be included with a SAML protocol message transmitted with
this binding. The value MUST NOT exceed 80
bytes in length and SHOULD be integrity protected by the entity
creating the message independent of any other protections that may or
may not exist during message transmission. Signing is not realistic
given the space limitation, but because the value is exposed to
third-party tampering, the entity SHOULD ensure that the value has not
been tampered with by using a checksum, a pseudo-random value, or
similar means. If a SAML request message is accompanied by RelayState
data, then the SAML responder MUST return its SAML protocol response
using a binding that also supports a RelayState mechanism, and it MUST
place the exact data it received with the request into the
corresponding RelayState parameter in the response. If no such value
is included with a SAML request message, or if the SAML response
message is being generated without a corresponding request, then the
SAML responder MAY include RelayState data to be interpreted by the
recipient based on the use of a profile or prior agreement between the
parties
For the other bindings a similar section exists. So as #nzpcmad says: it's not mandatory to include it in a request.
Reading SAMLv2 core spec "Single Logout Protocol" XML schema for the SAML LogoutRequestType
<element name="LogoutRequest" type="samlp:LogoutRequestType" />
<complexType name="LogoutRequestType">
<complexContent>
<extension base="samlp:RequestAbstractType">
<sequence>
<choice>
<element ref="saml:BaseID" />
<element ref="saml:NameID" />
<element ref="saml:EncryptedID" />
</choice>
<element ref="samlp:SessionIndex" minOccurs="0" maxOccurs="unbounded" />
</sequence>
<attribute name="Reason" type="string" use="optional" />
<attribute name="NotOnOrAfter" type="dateTime" use="optional" />
</extension>
</complexContent>
</complexType>
<element name="SessionIndex" type="string" />
does not mention the RelayState Element. The "Single Logout Profile" in the SAMLv2 profile spec does also not mention RelayState.
I would say this suggests that RelayState (which is a request parameter, so can only be used in a front-channel binding) is not mandatory.
Is it possible to publish a SOAP service as a REST API directly in the API manager? Is it possible to convert the call and expose REST to end user while calling the SOAP?
If possible, how?
Thanks.
This might be what you are looking for. This has can be done as mentioned below.
If you want to expose multiple operations using the same API in a RESTful manner you can modify the sequence in the post using the following guidelines.
1) Create a request URI to map to each operation in your backend SOAP service when designing the REST API in API Manager.
2) Using the filter mediator (which acts as a conditional statement in programming) you can filter out from the request URI(operation) and construct the required payload accordingly.
The below block would be repeated corresponding to your various operations mapping your backend web service.
The logic here would be if the request URI of the API is X route to operation Y of the SOAP service.
<!-- this filters out the operations of your API -->
<property expression="json-eval($.operation)" name="operation" />
<filter regex="menu" source="$ctx:operation">
<header description="SOAPAction" name="SOAPAction" scope="transport" value="http://ws.cdyne.com/PhoneVerify/query/CheckPhoneNumber"/>
<!-- We are storing the input values which the end users input for these values into properties -->
<property name="uri.var.phoneNumber" expression="$url:PhoneNumber"/>
<property name="uri.var.licenseKey" expression="$url:LicenseKey"/>
<!-- Since we do not want the URL pattern we mentioned to be sent to the backend we need to add the below property to remove it -->
<property name="REST_URL_POSTFIX" scope="axis2" action="remove"/>
<!-- Now we need to create the actual payload which the backend requires. For that we use the payload factory mediator -->
<payloadFactory description="transform" media-type="xml">
<format>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:quer="http://ws.cdyne.com/PhoneVerify/query">
<soapenv:Header/>
<soapenv:Body>
<quer:CheckPhoneNumber>
<quer:PhoneNumber>$1</quer:PhoneNumber>
<quer:LicenseKey>$2</quer:LicenseKey>
</quer:CheckPhoneNumber></soapenv:Body>
</soapenv:Envelope>
</format>
<args>
<arg expression="get-property(‘uri.var.phoneNumber’)"/>
<arg expression="get-property(‘uri.var.licenseKey’)"/>
</args>
</payloadFactory>
For further information on the above use case you can you can refer this post as reference on how such a custom extension sequence has been used to map a backend SOAP web service operations. With this you would be able to directly expose it as a REST API
Or you can simply create an SOAP based API in the WSO2 API Cloud or WSO2 API Manager and then pass the request payload along with the SOAP operation sent in the SOAP Action header so that you can call the different operations of your backend web service. You can see how this is used in the image below.
Managing WSDL operations using a single API
Hope this helps.
Regards.
yes. You can refer this blog post as reference. please note that there may be some differences as this was written for API manager Alpha version. Yet it is a good entry point.
I've got a secured Backbone.js app (that uses Spring security atm.), so a logged-in user must have a valid session-cookie (JSESSIONID). Now, if this session is invalidated (deleted, expired, whatever) and the user attempts to make a request, Spring security will return a 302 Error as an attempt to redirect the user to a login-form.
As is explained in this answer, this 302 response gets handled by the browser (it doesn't reach my app) so what is returned to my app is a 200 OK response with contenttype="text/html" (containing the login form).
Thats an issue, because when my Backbone model attempts to do a sync to a url, it expects JSON. If this sync happens without a valid session, the 200 "text/html" response is returned when "application/json" is expected, giving me a JSON parse error in jQuery.extend.parseJSON.
With great help from this question/answer, I've overridden the Backbone.sync method in order to use my own error handling. However, since the 302 never reaches my error handler I cannot override the redirect myself.
My situation is very similar to this question, however a final solution to the problem was never posted. Could someone please help me figure out the ideal way to ensure a redirect to the login page happens?
Instead of returning the login page with HTTP 200 OK, you should configure Spring Security to return HTTP 401 Unauthorized for unauthenticated AJAX requests. You can detect an AJAX request (as opposed to a normal page request) by checking for the X-Requested-With: XMLHttpRequest request header.
You can use the global $.ajaxError handler to check for 401 errors and redirect to the login page there.
This is how we've implemented it and it works nicely. I'm not a Spring guy, though, so I can't really help with the Spring Security configuration.
EDIT. Instead of custom coockie it will be better to use solution provided by #fencliff.
I think you can use some other field of XHR to detect this situation. A special coockie may do the trick.
You can define your own authentication failure handler from Spring Security side. At the moment when redirect to login page occurs you will be able to add some coockie to HttpServletResponse. Your custom Backbone.sync method will check this cookie. If it is present, it will launch your custom handler for this case (do not forget remove the coockie at the same time).
<sec:http ... >
<sec:form-login login-page='/login.html' authentication-failure-handler-ref="customAuthenticationFailureHandler" />
</sec:http>
<bean id="customAuthenticationFailureHandler" class="com.domain.CustomAuthenticationFailureHandler" />
CustomAuthenticationFailureHandler must implement org.springframework.security.web.authentication.AuthenticationFailureHandler interface. You can add your coockie and then call default SimpleUrlAuthenticationFailureHandler.onAuthenticationFailure(...) implementation.
I have been trying to invoke a rest operation from my wso2 ESB and was successful in invoking the rest post method from WSO2 ESB. But, un luckily i was not able to access the data that i posted, neither through request parameters nor through request attributes.
PS: I don't want to frame a get kind of URLs for my post request.
is there a solution to this ?
You need to use the correct content type so it will preserve POST request data.This post will help you to understand the reason.
Edit.
1) Add the following entry to axis2.xml in message builders.
<messageBuilder contentType="application/x-www-form-urlencoded"
class="org.apache.synapse.commons.builders.XFormURLEncodedBuilder"/>
2) then access the required parameter in esb using
<property name="NameOfTheProperty" expression="//xformValues/NameOfTheProperty/text()"/>