How to access protected assets in Play Silhouette with JWT Authenticator - scala

I have Play with Silhouette authentication and authorization configured using the JWTAuthenticator. This authenticator works by reading the X-Auth-Token header, which is a jwt, to identify user in every request. This works fine for REST endpoints.
Now I have images that only owners should be able to access it, and I would like to use those in background-image css property (this is a requirement). In such scenario I'm not able to set the request header hence the request will be denied.
The next natural step is to embed the token in the background-image url itself as an url parameter. However I don't know then how to proceed at the server side. How can I tell the JWTAuthenticator to use the token in the url if not X-Auth-Token header is present?

Ok, I'm sharing here my founds so hopefully this can help others. While digging into silhouette code I found that we can easily configure from which part(s) of the request (header, query string, ...) we want to read the token. By default the jwt token is read from the X-Auth-Token header, but we can configure the JWTAuthenticator to read the token also from a query string variable:
val config =
configuration.underlying
.as[JWTAuthenticatorSettings]("silhouette.authenticator")
// this is the important line of code
.copy(requestParts = Some(Seq(RequestPart.Headers, RequestPart.QueryString)))
new JWTAuthenticatorService(config, None, encoder, idGenerator, clock)
Now if you want to use a protected asset behind a controller with a silhouette.SecureAction then you just need to add the X-Auth-Token as query string parameter to the url:
.my-class {
background-image: url("/image?X-Auth-Token=........")
}

Related

storing and sending jwt httponly cookie, and csrf token with postman

I have a flask API, with jwt authentication, on a httponly cookie. I installed interceptor, added the domain(with HTTPS) to the list, and enabled the requests and cookies interception.
but still,
how do I make postman send the cookie I got from logging in to the server? usually, with a simple front-end, it just happens, so I didn't think about it.
all the methods I found in postman documentation, including specifying the value with the token, but I don't have it, since I can't access the httponly cookie. (or can I?)
must I access the cookies? can it be done automatically like simply sending requests from the front-end?
any guidance will be appreciated
After a full evening of research, I did two things to make it work -
in the login request, I added a "test" script(a post-request script in postman), with the following code:
const csrf_token = pm.response.headers.get("set-cookie");
const edited_token = csrf_token.split(/[;=]/)[1];
pm.environment.set("X-CSRF-TOKEN", edited_token);
console.log(csrf_token.split(/[;=]/)[1]);
First, I got the cookie from the response, and then used a regex to separate only the token value, and set it as an environment variable. this way, I could add it as a header later, for accessing protected URLs.
The second step was to add a pre-scrit in any request with a protected URL -
in the pre-request tab, I added the following:
pm.request.headers.add({
key: 'X-CSRF-TOKEN',
value: pm.environment.get("X-CSRF-TOKEN")
});
Which only added the same token I took earlier from the "X-CSRF-TOKEN" environment variable and set it to the header.
Mission accomplished :)
I hope it will help others who bumped into this

Swagger Inspector version of C# call failing when using token

I have the following code:
string tokenValue = "221e0a91-6530-4790-a969-d1da75b0afd2";
// Configure httpClient to use the above token.
httpClient.DefaultRequestHeaders.Add("token", tokenValue);
The subsequent calls (HEAD, POST, GET) all work fine.
When I try to do the same thing using Swagger Inspector, it fails. I am able to get a token using Swagger Inspector site, and I place the token into a HEAD call as follows:
But as I said, the call fails, with "Authorization has been denied for this request." message returned as an XML file.
I also tried the two other options available on the same page: Basic Authentication, and OAuth 2.0/JWT, all with HTTPS. They all fail.
How can I go about understanding why it's failing?
Also: Is what I am using above called "Bearer Authentication"?
I have below 2 things to mention from your screenshot:
Response for HEAD method never contains the response body, it always contains the response headers
for more details of HEAD: HEAD Request
But in your case response-body is also present (maybe of CML content type).
You should use OAuth 2.0/JWT option on the same page to pass the token along with your request.
To answer your question related to Bearer Authentication:
No, the one you are trying to use is not at all Bearer Authentication.
In your case, "token" will be considered as Custom/User HTTP Header.

Retrieve Pyramid's auth_tkt via HTTP response headers on mobile client

I am writing a mobile iOS application, which communicates with a Pyramid app on the backend. I am currently using Pyramid's built-in AuthTktAuthenticationPolicy.
I've met some speed bumps while attempting to authenticate via a mobile client (iPhone). For starters, how would I send and retrieve the auth_tkt cookie that is set by Pyramid.
I understand how this works with a web browser, but, if I want to send this "auth_tkt cookie" in the HTTP response, how can I accomplish this? How do I actually get the auth_tkt secret string. For example, what if I'd like to return it in the JSON body or a custom header of my choosing rather than as the cookie set by Pyramid's remember function?
Secondly, in future requests sent by the client what header do I set with the auth_tkt secret string so that Pyramid recognizes it and appropriately authenticates the client?
Using the Pyramid Helper Classes here, it looks like you can create your own auth_tkt and access it as well. Example from docs:
token = AuthTicket('sharedsecret', 'username',
os.environ['REMOTE_ADDR'], tokens=['admin'])
val = token.cookie_value()
The headers is a webob ResponseHeaders object, it derives from webob multidict. You can get it value by using this:
set_cookie = request.response.headers['set-cookie']
You can refer this link: webob multidict

How do I send REST request with the oauth parameters added in the URI (as input parameters)

I have a specificaiton for a project that accesses a third party service -RESTfully and requires oAuth authentication. [It accepts only GET method, and no access token is required since I will be trying to access the protected resources using consumer key and consumer secret values along with the oauth parameters.]
I am using SoapUI-Pro 4.6.1 and tried sending a GET request with oauth parameters as authorization header using signpost method, but my project accepts only when the oauth parameters are sent in the URL.
So, when I generate oauth signature, nonce and timestamp values manually using this link- http://oauth.googlecode.com/svn/code/javascript/example/signature.html and update it in my request URL, it is working fine.
Sample URL: http://sample.com/content/?oauth_consumer_key=abc&oauth_nonce=FUINSzmeoDh&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1384436218&oauth_version=1.0&oauth_signature=ISAsa2LJt3tVhgCnbL/GQszcZbc=
Instead of this manual step, is there a way to generate oauth_signature, oauth_timestamp & oauth_nonce values automatically and then use it in the request URI as an input parameter?
Thanks in advance!
In the version SoapUI Version 5.0.0 and above, you have an option to add query parameters.
On clicking the text box on parameters, we get a window with options to add parameters. Refer to the image.

Facebook server-side authentication flow: is this the right "code?"

I'm using FB.login on the JS client and want to verify the user's identity on the server. So, the client gets a signedRequest from facebook and sends it to the server. The server splits on the period, and decodes the second part of the signedRequest into a json object.
What should I be using for "code" when I send my server-side request to
https://graph.facebook.com/oauth/access_token?
client_id=YOUR_APP_ID
&redirect_uri=YOUR_REDIRECT_URI
&client_secret=YOUR_APP_SECRET
&code=CODE_GENERATED_BY_FACEBOOK
My decoded json looks something like:
{"algorithm":"HMAC-SHA256","code":"2.AQCPA_yfx4JHpufjP.3600.1335646800.1-5702286|l11asGeDQTMo3MrMx3SC0PksALj6g","issued_at":1335642445,"user_id":"5232286"}
Is that the code I need? Does it need to be B64 encoded? If this isn't the code, what code should I use?
_
What I've tried:
The request I'm trying to use is:
https://graph.facebook.com/oauth/access_token?client_id=295410083869479&redirect_uri=https://squaredme.appspot.com/facebookredirect&client_secret=44f1TOPSECRETbb8e&code=2.AQCPA_yfx4JHpufjP.3600.1335646800.1-5702286|l11asGeDQTMo3MrMx3SC0PksALj6g
but this returns the error:
{"error":{"message":"Error validating verification code.","type":"OAuthException","code":100}}
I can't tell if this is because I'm using a bad code, or what. Noteably, this is running on my local dev server, and squaredme.appspot.com definitely does NOT resolve to my IP. I don't know if facebook checks that or what - I'm assuming I'd get a better error message. Thanks for any direction!
You are trying to somehow combine the two flows together and that's why things don't work well.
When facebook POSTs into the iframe with your app url and a signed request there are two options, the easy one being that the user is already authenticated and then the signed request will have all the necessary data (including a signed request), then you just load the canvas page and use the JS SDK to get an access token there as well, but in this case there's no need to use the FB.login (since it opens a popup and will automatically close it), you can use the FB.getLoginStatus method which won't annoy the user.
If the user is not authenticated then the sign request will be missing the things you need to use the graph api.
You then redirect the user to the auth dialog, and since you are loaded in an iframe you'll need to return a html response which redirects the parent window using javascript, like:
top.location.href = "AUTH_DIALOG_URL";
When the use is done (accepted or rejected the app) he will be redirected to the "redirect_uri" you added as a parameter to the auth dialog.
If the user accepted your app then you'll be getting the "code" parameter in the query string.
You then take the code, exchange it with an access token as you posted in your question, and then redirect the user back to "apps.facebook.com/YOUR_APP".
When the page then loads the user is already authenticated and you'll be getting a full signed request.
I hope this clarifies things for you, recheck the Server-Side flow it pretty much covers it all.
I also had some trouble with that, then I found the solution here in StackOverflow.
There are two kinds of "code" provided by facebook. One comes inside the signedRequest in the cookie generated by the client-side flow. The Facebook's JS SDK handles this codes and get a access token without telling us anything.
The other type of code comes attached as a query to your redirect URI (http://www.yoururl.com/index.php?code=AAAgyiaus...), when you navigate to OAuth URL (server-side flow). With this code, you go to a Token URL and get your access token.
When you are using the server-side flow, you need to indicate a redirect URI both in the OAuth URL AND in the Token URL, and they have to be exactly the same, so a missing slash or a query string can be a lot of problem.
The codes are different from each other. When you use the both things together, appears to be impossible to get a access token using the code that was inside the cookie's signedRequest.
BUT, it is not. The magic is: the code from signedRequest is associated with NO URI, so as long as the redirect_uri is a mandatory field, all you have to do is to pass it blank when you navigate to the Token URL.
So the final solution is: grab the signedRequest from the cookie, parse it in your server to obtain the code, then read the Token URL:
https://graph.facebook.com/oauth/access_token?
client_id=YOUR_APP_ID
&redirect_uri=&client_secret=YOUR_APP_SECRET
&code=CODE_INSIDE_THE_SIGNED_REQUEST
It looks like a hack, so I don't know how long it's gonna work, but it's working right now.