I am trying to test a Web API using Postman on a project which I have inherited from previous developers. All I know so far is that Authentication has been configured using ASP.Net Identity and Identity Server 4.0 which implements OAuth and issues short lived JSON Web Tokens (JWT) and Refresh Tokens.
If I navigate to the development website, log in (successfully), and use Chrome Developer Tools to inspect the initial log in request I can see that the body of the request contains a Form with 3 fields; userName, password and returnUrl. If I right-click on the request I can copy the request as cURL (bash) and in Postman I can import the data to create a new request. If I send the request I get a status 200 OK back and the response includes 6 cookies. However the body of the response contains an htlm page which Postman can't render and a message You need to enable JavaScript to run this app.
I'm lost now as to how I can use the response to authenticate a request for some data. Is the Token I need contained within one of the cookies? How do I extract the Token and use it within a request for some data? Any advice or suggestions would be very welcome.
Normally, with JavaScript enabled in the browser, <form> would be automatically posted to its' destination defined in action, using method. JavaScript would do somethign like the following:
window.addEventListener('load', function(){document.forms[0].submit();});
So without JavaScript, you would need to somehow parse the form that you received and recreate equivalent request.
The form, received upon successful login, contains data that should be sent back to your origin website, to authenticate the end-user.
For example, form's body contains hidden input fields, defined by OpenID protocol:
...
<input type='hidden' name='token_type' value='Bearer' />
<input type='hidden' name='expires_in' value='600' />
...
Form action attribute points back to sign-in endpoint on your website. For example:
<form method='post' action='https://{hostname:post}/signin-oidc'>
Related
I'm trying to learn Sails JS and obviously REST API.
I've created a user model wich I think works fine (it communicates datas with my db). I've also created a signup controller with 4 needed inputs to store a new record in my user collection. (Some other datas are generated by this controller to complete the record at the moment of the registration)
I would like to test this controller with POSTMAN, so I go to my routes.js and see :
'POST /api/v1/entrance/signup': { action: 'entrance/signup' },
But when i enter a POST request at 192.168.1.13:1338/api/v1/entrance/signup with my 4 needed inputs declared I have this answer : Forbidden
I don't know what I do wrong. I've also enabled rest, shortcuts and actions in my blueprints.js
Does someone has an idea ? :)
The issue is indeed related to cross-site request forgery, but disabling the corresponding security rule altogether is quite obviously not a solution. CSRF and its treatment in sailsjs are well described in the corresponding part of the manual. In short, for POSTs to work you have to include _csrf in your requests. E.g. in a view template:
<form>
<input type="hidden" name="_csrf" value="<%- _csrf %>" />
</form>
As said below, removing CSRF protection is not an answer as it may expose the api to a security breach. I currently use JWT but it doesn't seems to be as secure as CSRF token so the only right way is to include the token in every HTTP's request header.
(I am not talking about authenticating calls to RESTful API. I am talking about creating login logic for user via RESTful API.)
When user access any page of my site, a servlet filter will intercept the request and check if necessary authentication info exists in session. If not exists, user will be directed to login page.
On the login page, an ajax call is made to a RESTful API on server with username and password. Depending on the return status of that RESTful API, the JavaScript on the page will decide whether let user into the site. Note that the actual authentication logic is still carried out on server side. Client JS only acts based on the result from server.
On the server, the RESTful login API will check the submitted username/password and see if it is contained in DB. If exists, it will store necessary authentication info into the session so future requests from the same client will not be blocked.
My questions are:
Is this login logic sound?
Because session is involved, the RESTful login API is kind of not stateless. So is it still RESTful?
Here's my code:
login.js
// login.js
$(function () {
$('#submitDiv').click(doLogin);
});
function doLogin() {
$('#resultDiv').text("start!");
user = new Object();
user.username = $('#txtUsername').val();
user.pwd = $('#txtPassword').val();
$.ajax({
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
'type': 'POST',
'url': 'doLogin.sm',
'data': JSON.stringify(user),
'dataType': 'text',
'success': loginSuccessful,
'complete': function (jqXHR, textStatus) {
$('#resultDiv').text("complete with:" + textStatus);
}
});
}
function loginSuccessful() {
//if referrer is null, jump to dashboard, else jump to referrer.
var referer = getUrlVars()['referer'];
if (referer) {
window.location.replace(referer);
}
else {
window.location.replace('dashboard.html');
}
}
login.html:
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Cloud - Login page</title>
<link rel="stylesheet" type="text/css"
href="resources2/css/bootstrap.css">
<meta charset="utf-8">
<!--force to use the latest IE engine-->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="resources2/js/jquery-1.11.3.js"></script>
<script src="resources2/js/bootstrap.js"></script>
<script src="resources2/js/pagejs/common.js"></script>
<script src="resources2/js/pagejs/login.js"></script>
</head>
<body>
<h1>My Login Page</h1>
<div id="loginDiv">
<input id="txtUsername" type="text" value="test">
<input id="txtPassword" type="password" value="test">
<div id="submitDiv" class="btn btn-default">
Login
</div>
<div id="resultDiv"></div>
</div>
</body>
</html>
If your JavaScript decides whether to allow the user to get pages from your site, what is stopping the user from setting a breakpoint in the JavaScript code and changing the outcome of the authentication process?
Authorization decisions need to happen on the server as you can never trust the client (browser).
Your site needs to verify at the server side that the user is authenticated. This is typically done by sending some kind of implicit authentication info along with the request that the server can verify and the client cannot forge.
I don't see that happening in your design. But why are you trying to design your own authentication mechanism? Why not use a standard protocol like WS-Federation, SAML-P, or OpenID Connect for this?
Session state on the client (not on the server)
That's what Roy Thomas Fielding, The REST Godfather, said in his dissertation regarding the stateless constraint:
5.1.3 Stateless
[...] each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client. [...]
So, if you are keeping the session state on the server, it's not REST.
In REST you won't have a session on the server and, consequently, you won't have a session identifier.
Each request must contain all data to be processed
Each request from client to server must contain all of the necessary information to be understood by the server. With it, you are not depending on any session context stored on the server.
When accessing protected resources that require authentication, for example, each request must contain all necessary data to be properly authenticated/authorized. It means the authentication will be performed for each request.
And authentication data should belong to the standard HTTP Authorization header. From the RFC 7235:
4.2. Authorization
The Authorization header field allows a user agent to authenticate
itself with an origin server -- usually, but not necessarily, after
receiving a 401 (Unauthorized) response. Its value consists of
credentials containing the authentication information of the user
agent for the realm of the resource being requested. [...]
Basic authentication
The Basic Authentication Scheme, defined in the RFC 7617, is a good start for securing a REST API:
2. The 'Basic' Authentication Scheme
The Basic authentication scheme is based on the model that the client
needs to authenticate itself with a user-id and a password for each
protection space ("realm"). [...] The server will service the request only if it can validate
the user-id and password for the protection space applying to the
requested resource.
[...]
To receive authorization, the client
obtains the user-id and password from the user,
constructs the user-pass by concatenating the user-id, a single
colon (":") character, and the password,
encodes the user-pass into an octet sequence,
and obtains the basic-credentials by encoding this octet sequence
using Base64 into a sequence of US-ASCII
characters.
[...]
If the user agent wishes to send the user-id "Aladdin" and password
"open sesame", it would use the following header field:
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
[...]
Remember the HTTPS is your best friend to prevent the man-in-the-middle attack.
Tokens
If you don't want sending the username and the password over the wire for every request, you can consider creating a token based authentication. In this approach, you exchange your hard credentials (username and password) for a token which is sent in each request.
Again, the authentication must be performed for every request.
Basically, the token can be opaque (which reveals no details other than the value itself, like a random string) or can be self-contained (like JSON Web Token).
Random String: A token can be issued by generating a random string and persisting it to a database with an expiration date and with a user identifier associated to it.
JSON Web Token (JWT): Defined by the RFC 7519, it's a standard method for representing claims securely between two parties. JWT is a self-contained token and enables you to store a user identifier, an expiration date and whatever you want (but don't store passwords) in a payload, which is a JSON encoded as Base64. The payload can be read by the client and the integrity of the token can be easily checked by verifying its signature on the server. You won't need to persist JWT tokens if you don't need to track them. Althought, by persisting the tokens, you will have the possibility of invalidating and revoking the access of them. To find some great resources to work with JWT, have a look at http://jwt.io.
There are many databases where you can persist your tokens. Depending on your requirements, you can explore different solutions such as relational databases, key-value stores or document stores.
The default process when authenticating user on OpenAM/OpenSSO works with a 302 http redirection, opening OpenAM/OpenSSO authentication formular. The original URL is stored into "goto" parameter, which allows OpenAM/OpenSSO to redirect the user back on orignal URL after correct authentication.
This works well when using HTTP GET method (i.e. when entering URL), but it is not suitable for POST method. For instance, if the session expires while the user posts a HTML form, the data are lost because HTML form inputs are not present in goto parameter.
Do you know it it is possible to configure J2EE Agent in order it re-posts user HTML form after valid authentication ?
Both the Java EE and the Web agents support post data preservation, see the documentation.
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.
If I visit the link http://mega.1280.com/file/EKOZKE/, enter the captcha code and click the Download button, I can download the file.
I wonder if I can submit the form without clicking the 'Download' button? I mean typing the captcha code directly on the address bar and hit Enter?
I try http://mega.1280.com/file/EKOZKE/?code_security=xxxxxx where 'code_security' is the name of the textbox of the captcha code but it failed. Any ideas?
The form has a POST method. You can't emulate a POST request with a different url, that's what GET requests do.
Even if the server doesn't check the method of the request, you still have to provide every mandatory data. If you look at what is sent by the form, you'll see there are 3 other parameters (action, btn_download, file_id), and more importantly several cookies that the server need to recover your php session (PHPSESSID), which is in turn needed to match your security_code with the provided CAPTCHA.
Bottom line: you can emulate the request, but not by submitting a simple GET request. You have to use a real user agent, one that is able to send post requests and handle cookies.
...But of course, that's exactly what CAPTCHA are here to prevent you to do :-).
edit: to reply to your comment "I just want to find out the technique that this website use to submit form." :
This website doesn't submit the form, actually. It's your browser that submits the form, and it does so by conforming to HTML and HTTP standards. On the webpage, the form is coded
<form name="frm_download" method="post" action="">
So when you click on the "submit" button, your browser collects all the data from the inputs (text, hidden, whatever) and sends a HTTP POST request to the same url that the form originated from, with a bunch of HTTP headers (including a Cookie header that contains all the stored cookies information attached to this server domain) and a body containing the form data : a list of key/value pairs.
The server receives the request. It can check that it's actually a POST request. It can and will retrieve all submitted pairs of data (parameters). It can retrieve the cookies, and will do so to restore your php session. It will then compare your security_code parameter with the correct data stored in your php session. If the CAPTCHA matches, then it will send you a response containing the file pointed by your file_id parameter.