I've never used SAML before and am a bit confused. I thought I could just base64 encode xml and a key and be on my way, but apparently its not that simple.
I have to send a SAMLRESPONSE to a post method
<form method="post" action="%ACS" ...>
<input type="hidden" name="SAMLResponse" value="%RESPONSE" />
<input type="hidden" name="RelayState" value="%RELAYSTATE" />
...
</form>
The action is their URL and the SAMLRESPONSE I generate on my end with the certificare or IDP MEta data and the assertation. I thought I could encode my xml
<samlp:Response xmlns:samlp='urn:oasis:names:tc:SAML:2.0:protocol'xmlns:saml='urn:oasis:names:tc:SAML:2.0:assertion'ID='identifier_1'Version='2.0'IssueInstant='2004-12-05T09:22:05Z'Destination='https://sp.example.com/SAML2/SSO/POST'> <saml:Issuer>https://idp.example.org/SAML2</saml:Issuer> <samlp:Status> <samlp:StatusCode Value='urn:oasis:names:tc:SAML:2.0:status:Success'/> </samlp:Status> <saml:Assertion xmlns:saml='urn:oasis:names:tc:SAML:2.0:assertion'ID='identifier_2'Version='2.0'IssueInstant='2004-12-05T09:22:05Z'> <saml:Issuer>https://idp.example.org/SAML2</saml:Issuer> <ds:Signature xmlns:ds='http://www.w3.org/2000/09/xmldsig#'>...</ds:Signature> <saml:Subject> <saml:NameID Format='urn:oasis:names:tc:SAML:2.0:nameidformat:uid'> " + employeeID + " </saml:NameID> <saml:SubjectConfirmation Method='urn:oasis:names:tc:SAML:2.0:cm:bearer'> <saml:SubjectConfirmationData Recipient='https://sp.example.com/SAML2/SSO/POST'NotOnOrAfter='2004-12-05T09:27:05Z'/> </saml:SubjectConfirmation> </saml:Subject> <saml:Conditions NotBefore='2004-12-05T09:17:05Z'NotOnOrAfter='2004-12-05T09:27:05Z'> <saml:AudienceRestriction> <saml:Audience>https://sp.example.com/SAML2</saml:Audience> </saml:AudienceRestriction> </saml:Conditions> <saml:AuthnStatement AuthnInstant='2004-12-05T09:22:00Z'SessionIndex='identifier_2'> <saml:AuthnContext> <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:u nspecified</saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement> </saml:Assertion> </samlp:Response>
The provider reccomended I use ADFS 3.0 but I'd like to avoid changing anything on server. Is there a different package I could use to help all this?
Don't try and roll your own. Use a client side SAML stack e.g. SAML : SAML connectivity / toolkit.
This stack talks SAML to an IDP like ADFS. You need to configure ADFS with the SAML parameters of your client side stack.
Related
I am trying to use APIM to send a request through to a back-end App Service which requires the client to be authorised with roles. When I connect directly to the App Service with an App Registration with the roles this works as expected or when I send via APIM without using Managed Identity for the authorisation.
I would like to be able to have the Athorisation header replaced using the System Assinged Managed Identity but when it adds the new bearer token it is missing the roles section when I inspect the JWT Token in jwt.io.
The policy looks like this:
`
<policies>
<inbound>
<base />
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Missing Token or Invalid one yo!">
<openid-config url="https://login.microsoftonline.com/{my_tenant}/.well-known/openid-configuration" />
<required-claims>
<claim name="aud">
<value>api://{my_backend_app_reg}</value>
</claim>
<claim name="roles" match="any" separator=",">
<value>{my_role}</value>
</claim>
</required-claims>
</validate-jwt>
<set-header name="ClientAppRegId" exists-action="override">
<value>#(context.Request.Headers.GetValueOrDefault("Authorization").AsJwt()?.Claims.GetValueOrDefault("appid"))</value>
</set-header>
<set-header name="Ocp-Apim-Subscriptionkey" exists-action="delete" />
<set-header name="Authorization" exists-action="delete" />
<authentication-managed-identity resource="api://{my_backend_app_reg}" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
`
Have ensured the App Registration that seems to be tied to the APIM Managed Identity has the roles set within the API permissions section and confirmed when sending via Postman/Insomnia that the roles are in the returned token when manually requested.
Have checked the token used in the trace and it looks almost the same but missing the roles section.
My back-end service then authenticates as expected but then fails at the authorisation on the controllers as the roles are not present in the token
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.
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
We are considering using IdentityServer3 to provide federated authentication / authorisation using oAuth2 and OpenID. Our prototypes are promising and we have a basic framework up and running.
However, we have hit a problem...
After the user is authenticated the framework returns the Identity and Access tokens back to the client application as parameters of the redirect URI. Due to the nature of the application(s) we are looking to secure there is a need to have quite complex claims/roles. This results in fairly large tokens*. So large that they go beyond the maximum URI length that browsers support and therefore breaks.
So my question is, does anybody know if is possible to configure Identity Server to POST the tokens back rather than GET? Or is there another solution that does not deviate away from standards/specification?
*The claims we are talking about here are not actually that large. As an example here is a claim from the IdentityServer3 code samples
Claims = new Claim[]
{
new Claim(Constants.ClaimTypes.Name, "Alice Smith"),
new Claim(Constants.ClaimTypes.GivenName, "Alice"),
new Claim(Constants.ClaimTypes.FamilyName, "Smith"),
new Claim(Constants.ClaimTypes.Email, "AliceSmith#email.com"),
new Claim(Constants.ClaimTypes.Role, "Admin"),
new Claim(Constants.ClaimTypes.Role, "Geek"),
new Claim(Constants.ClaimTypes.WebSite, "http://alice.com"),
new Claim(Constants.ClaimTypes.Address, "{ \"street_address\": \"One Hacker Way\", \"locality\": \"Heidelberg\", \"postal_code\": 69118, \"country\": \"Germany\" }")
}
If we add another claim to this, of the same size as the address claim, then we hit the URI length issue.
That's not quite correct. It's the responseMode that needs to be changed to form_post.
var authorizationUri = new Uri(
client.CreateAuthorizeUrl(
clientId: "myclient",
responseType: "code id_token token",
scope: "openid Resource roles",
redirectUri: "oob://application/tokens",
responseMode: "form_post"));
IdentityServer will then encode the response parameters as HTML form values and POST these back to your client.
<form method="post" action="oob://application/tokens">
<input type="hidden" name="code" value="aca7b48d8a944ae6a9b91283e26b1740" />
<input type="hidden" name="id_token" value="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ" />
<input type="hidden" name="access_token" value="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ" />
<input type="hidden" name="token_type" value="Bearer" />
<input type="hidden" name="expires_in" value="3600" />
<input type="hidden" name="scope" value="openid Resource roles" />
<input type="hidden" name="session_state" value="AHzV1QYcGi-W95OYJAganx0piP5y_km_4q9qsuvAacg.e8ca5c9876007e40bf3cc89314c86c0f" />
</form>
If the tokens are too large for delivery through a front channel binding, you should switch to a backchannel binding, i.e. switch the response_type to code and get the tokens directly from the token endpoint.
There's also an option to use the POST transport method in the front-channel but it is an optional extension to OAuth 2.0 (http://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html) and I don't think IdentityServer supports it (yet).
I am attempting to use JSoup for parsing HTML, logging into an account and then parsing additional HTML.
There are several tests I have performed on simple HTML, but I picked a website written in JSP that I have an account on, but I am not having any luck attempting to log into the site..
From the HTML, I have the following fields as part of the input:
input id="loginPopup" type="text" size="25" value="" name="/atg/userprofiling/ProfileFormHandler.value.login" maxlength="46"
input type="hidden" value=" " name="_D:/atg/userprofiling/ProfileFormHandler.value.login"
and
input id="passwordPopup" maxlength="25" name="/atg/userprofiling/ProfileFormHandler.value.password" value="" type="password" autocomplete="off" size="25"
input name="_D:/atg/userprofiling/ProfileFormHandler.value.password" value=" " type="hidden"
After retrieving the HTML, I am executing the following:
doc = Jsoup.connect(MAIN_URL)
.data("/atg/userprofiling/ProfileFormHandler.value.login", "xxxxxx#yahoo.com")
.data("/atg/userprofiling/ProfileFormHandler.value.password", "<password>");
.post();
..actually, I have tried several combinations, but am having no success.. I end up getting the "wrong userid/password" screen...
I have also used JSoup to ensure I have the proper name value by:
Element input = doc.getElementById("loginPopup");
String inputName = input.attr("name");
I have been looking for other JSoup examples, and thought maybe someone here might have some insight...
I will be redirected to a secured (HTTPS) page, but I don't think that is the issue. I am assuming it something to do with the strange "name" values of the HTML inputs..?
Thanks
Use a chrome extension called POSTMAN to try simulate the login, Oracle ATG usually needs more fields to login than just Login and Password, open chrome Developer Tools and check the Network while doing a real login to the site, then you will be able to see all the paramenters needed to simulate the login from code.
[]s