Redirect Uri too long when using IdentityServer3 - oauth

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).

Related

Issues with using d2l remote plugins (insert stuff cim) example not working

I am new to Brightspace and been fiddling with the remote plugins sample (logo). I can load the sample logo project, but cannot get it to insert into the page. I have uploaded the file but get a 404 error on submit. Can someone `
$( document ).ready(function() {
$('#submitFormButton').click( function() {
$.ajax({
url: "/getisfdetails",
data: {
image: $("input[name='image']:checked").val()
},
success: function(response){
$("input[name='lti_message_type']").val(response.lti_message_type);
$("input[name='lti_version']").val(response.lti_version);
$("input[name='content_items']").val(response.content_items);
$("input[name='oauth_version']").val(response.oauth_version);
$("input[name='oauth_nonce']").val(response.oauth_nonce);
$("input[name='oauth_timestamp']").val(response.oauth_timestamp);
$("input[name='oauth_consumer_key']").val(response.oauth_consumer_key);
$("input[name='oauth_callback']").val(response.oauth_callback);
$("input[name='oauth_signature_method']").val(response.oauth_signature_method);
$("input[name='oauth_signature']").val(response.oauth_signature);
$("#isfForm").prop('action', response.lti_return_url);
$("#isfForm").submit();
}
});
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
src="https://code.jquery.com/jquery-3.2.1.min.js"
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
crossorigin="anonymous"></script>
<body>
<h3>Select an logo:</h3>
<input type="radio" name="image" value="brightspace-logo.png"> <img src="../content/isf/brightspace-logo.png" alt="Brightspace Logo"><br />
<input type="radio" name="image" value="d2l-logo.png"> <img src="../content/isf/d2l-logo.png" alt="D2L Logo"><br />
<div hidden>
<form id="isfForm" method="POST">
<input type="hidden" name="lti_message_type" />
<input type="hidden" name="lti_version" />
<input type="hidden" name="content_items" />
<input type="hidden" name="oauth_version" />
<input type="hidden" name="oauth_nonce" />
<input type="hidden" name="oauth_timestamp" />
<input type="hidden" name="oauth_consumer_key" />
<input type="hidden" name="oauth_callback" />
<input type="hidden" name="oauth_signature_method" />
<input type="hidden" name="oauth_signature" />
</form>
</div>
<br />
<button id="submitFormButton">Submit</button>
</body>
` how do you set this cookie in the javascript? I believe a cookie needs to be set??? and I do not see how to set it? or maybe I am missing something else that is not noted in the documentation.
I would highly recommend you consider using LTI Advantage/1.3 instead of Remote Plugins. LTI provides a standards-based integration approach & a better developer experience.
https://community.brightspace.com/s/article/LTI-Integration-Guide
If you are working with a partner of D2L please get in touch with the partner team and technical assistance is available. Your information here is appreciated but we are glad to examine the full context and use case as these errors are not hugely uncommon during dev. Otherwise, I echo Paul's suggestion, but I understand if it is not immediately possible.
partners#d2l.com or talk with your team that knows D2L!
Depending on which browser you are in you might be seeing the recent effects of the third-party cookie blocking that the browsers are adopting. Because LTIs (both 1.1 and 1.3/Advantage) typically launch into iframe any access to those cookies are regarded as third party. This effectively means two things
You need to be aware of the cookie access routines where a user action must be taken to request access to the browser storage API using document.requestStorageAccess()
You need to be marking your cookies appropriately with the new SameSite cookie directives
Without these the browser will mark your cookie request as a 'Tracking cookie' and refuse to serve it along with the request or make it accessible via javascript.
An alternative is also to detect that the LTI launch is happening inside the an iframe and to bust that iframe out to a new window, or alternatively configure the launch inside Brightspace to not use a iframe at all.

Using SAML 2.0 to authenticate from .net mvc to another site

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.

Amazon s3 form post/upload redirecting to bucket after success on iOS safari/chrome only how to stop?

I have a web app that allows users to upload photos to an S3 bucket via HTML form. It works exactly as expected on all desktop browsers, which is to do nothing after a successful upload. However in iOS safari and iOS chrome, it redirects to the bucket. If I "Handoff" the page over to safari on my mac it is an xml response of the entire bucket, it appears.
Does anyone know why this would happen and how to fix it? Normally I can find something via google and the forums but I'm finding nothing!
We are not specifying "success action redirect" or "success action status" on our form.
Also, it works as expected in chrome on an android device.
We do not want any sort of redirect to occurs, we handle things on the client after clicking the submit/post button.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<div id ="mainContent">
<form action="https://s3.amazonaws.com/{!awsKeySet.Name}" method="post" enctype="multipart/form-data" id="uploadForm">
<input type="hidden" name="key" id="key" />
<input type="hidden" name="AWSAccessKeyId" value="{!awsKeySet.AWS_AccessKey_Id__c}" />
<input type="hidden" name="policy" value="{!policy}" />
<input type="hidden" name="signature" value="{!signedPolicy}" />
<input type="hidden" name="acl" value="{!acessType}" />
<input type="hidden" name="Content-Type" value="{!Content_Type}" />
<!--input type="hidden" name="success_action_status" value="201" /-->
<!--input type="hidden" name="success_action_redirect" value="{!ForRedirect}" /-->
<h4 class="fileToUpload">Select a File to Upload in AWS</h4><br />
<div class="row">
<input type="file" size="50" name="file" id="file" />
</div>
<div id="fileName"></div>
<div id="fileSize"></div>
<div id="fileType"></div>
<div class="row">
<input type="submit" value="Upload" id="btn_submit" />
</div>
<div id="progressNumber"></div>
</form>
</div>
<script>
$(document).ready(function () {
var _requestBucket;
$("#btn_submit").click(function(event){
//alert(1);
event.preventDefault();
var _file;
_file = $("#file").val().replace(/.+[\\\/]/, "");
console.log('_file '+ _file);
$("#key").val(_file);
$("#uploadForm").submit();
});
});
</script>
Thank you!
I wish someone could have shed more light on this but sadly, this is a bug in iOS webkit browsers. It appears to have been fixed in Android and Desktop. So, if anyone stumbles on this problem, included is the bugzilla link for it
Bugzilla link for Proper handling of HTTP 204
More detail : According to the amazon s3 docs
If the value is set to 200 or 204, Amazon S3 returns an empty document with a
200 or 204 status code.
If the value is set to 201, Amazon S3 returns an XML document with a
201 status code.
If the value is not set or if it is set to an invalid value, Amazon S3
returns an empty document with a 204 status code.
According to HTTP 1.1 -
10.2.5 204 No Content
The server has fulfilled the request but does not need to return an
entity-body, and might want to return updated metainformation. The
response MAY include new or updated metainformation in the form of
entity-headers, which if present SHOULD be associated with the
requested variant.
If the client is a user agent, it SHOULD NOT change its document view
from that which caused the request to be sent. This response is
primarily intended to allow input for actions to take place without
causing a change to the user agent's active document view, although
any new or updated metainformation SHOULD be applied to the document
currently in the user agent's active view.
The 204 response MUST NOT include a message-body, and thus is always
terminated by the first empty line after the header fields.
This is not happening in either webkit browsers for iOS, currently. Sadly. I cannot find a way around this, other for Apple to fix it!

File upload & Spring Security

Based on the Spring Security documentation, I setup a MultipartFileter as the following:
#Order(1)
public class SecurityWebAppInitializer
extends AbstractSecurityWebApplicationInitializer {
#Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
insertFilters(servletContext, new MultipartFilter());
}
In a file upload form, I can see a CSRF input with a not-null value in a HTML file (see the code below).
<form method="POST" enctype="multipart/form-data" action="/upload">
File to upload: <input type="file" name="file" /><br />
Name: <input type="text" name="name" /><br /> <br />
<input type="submit" value="Upload" />
Press here to upload the file!
<input type="hidden" name="_csrf" value="df94be7d-675d-428c-89e5-2ebf0b473c42" />
</form>
After submitting the form, I get an error as
HTTP Status 403 - Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.
type Status report
message Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.
description Access to the specified resource has been forbidden.
What is missing here?
This problem is resolved after changing the Java configuration of the application. The followings are those changes.
In AbstractAnnotationConfigDispatcherServletInitializer class, I add the MultipartFilter in the getServletFilters method and set the MultipartConfig with a MultipartConfigElement in customizeRegistration(ServletRegistration.Dynamic registration) method. A MutlipartConfigElement originally defined in WebMvcConfigurerAdapter class is removed. And a MultipartResolver defined in the class is unchanged.
The Java configuration was set up based on the original XML configuration of the application. The approach doesn't always work based on this case.

JSoup posting login data

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

Resources