How to maintain session state between two request with Groovy HttpBuilder - session

I'm working on a integration test where authentication is needed.
Session state (ie. cookie) seems not to be maintain beetween requests.
Is there a CookieManager or something like that ?
#Test
public void whenAuthenticatedUserRequestAForbiddenUrlShouldObtain403() {
def client = new RESTClient('http://127.0.0.1:8080/app/')
def login = client .post(
path: 'api/login.json',
body: [j_username: 'user', j_password: 'test'],
requestContentType: ContentType.URLENC)
def resp = client .get(path: 'forbidden-url')
assert (resp.status == 403)
==> FAILS status = 200
}

It looks to me like the problem is not losing session state but rather the 'forbidden-url' might not be specified as secure in the first place. If it were, it does not seem that client request request should succeed EVEN IF you login. Try removing the login at the top and if you still get 200, you probably don't have the URL secured anyway.

Related

Calling rest server from mobile app

Following on from https://lists.hyperledger.org/g/composer/message/91
I have adapted the methodology described by Caroline Church in my IOS app.
Again I can authenticate with google but still get a 401 authorization error when POSTing.
I have added the withCredentials parameter to the http header in my POST request.
does the rest server pass back the token in cookie ? I don't receive anything back from the rest server.
where does the withCredentials get the credentials from ?
COMPOSER_PROVIDERS as follows
COMPOSER_PROVIDERS='{
"google": {
"provider": "google",
"module": "passport-google-oauth2",
"clientID": "93505970627.apps.googleusercontent.com",
"clientSecret": "",
"authPath": "/auth/google",
"callbackURL": "/auth/google/callback",
"scope": "https://www.googleapis.com/auth/plus.login",
"successRedirect": "myAuth://",
"failureRedirect": "/"
}
}'
the successRedirect points back to my App. After successfully authenticating I return to the App.
Got this working now. The App first authenticates with google then exchanges the authorization code with the rest server.
The Rest server COMPOSER_PROVIDERS needs to be changed to relate back to the app.
clientID is the apps ID in google,
callbackURL and successRedirect are reversed_clientID://
The App calls http://localhost:3000/auth/google/callback with the authorization code as a parameter.
this call will fail, but an access_token cookie is written back containing the access token required for the rest server.
The user id of the logged in user is not passed back, when exchanging the code for a token with google we get back a JWT with the details of the logged in user. We need this back from the rest server as well as the token. Is there any way to get this ?
changing the COMPOSER_PROVIDERS means that the explorer interface to the Rest server no longer works.
func getRestToken(code: String) {
let tokenURL = "http://localhost:3000/auth/google/callback?code=" + code
let url = URL(string:tokenURL);
var request = URLRequest(url: url!);
request.httpMethod = "GET";
request.setValue("localhost:3000", forHTTPHeaderField: "Host");
request.setValue("text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8", forHTTPHeaderField: "Accept");
request.setValue("1", forHTTPHeaderField: "Upgrade-Insecure-Requests");
request.httpShouldHandleCookies = true;
request.httpShouldUsePipelining = true;
let session = URLSession.init(configuration: .default);
session.configuration.httpCookieAcceptPolicy = .always;
session.configuration.httpShouldSetCookies=true;
session.configuration.httpCookieStorage = HTTPCookieStorage.shared;
let task = session.dataTask(with: request) { (data, response, error) in
var authCookie: HTTPCookie? = nil;
let sharedCookieStorage = HTTPCookieStorage.shared.cookies;
// test for access_token
for cookie in sharedCookieStorage! {
if cookie.name == "access_token"
{
print(“Received access token”)
}
}
guard error == nil else {
print("HTTP request failed \(error?.localizedDescription ?? "ERROR")")
return
}
guard let response = response as? HTTPURLResponse else {
print("Non-HTTP response")
return
}
guard let data = data else {
print("HTTP response data is empty")
return
}
if response.statusCode != 200 {
// server replied with an error
let responseText: String? = String(data: data, encoding: String.Encoding.utf8)
if response.statusCode == 401 {
// "401 Unauthorized" generally indicates there is an issue with the authorization
print("Error 401");
} else {
print("HTTP: \(response.statusCode), Response: \(responseText ?? "RESPONSE_TEXT")")
}
return
}
}
task.resume()
}
have you authorised the redirect URI in your Google OAUTH2 configuration ?
This determines where the API server redirects the user, after the user completes the authorization flow. The value must exactly match one of the redirect_uri values listed for your project in the API Console. Note that the http or https scheme, case, and trailing slash ('/') must all match.
This is an example of an Angular 5 successfully using it Angular 5, httpclient ignores set cookie in post in particular the answer at the bottom
Scope controls the set of resources and operations that an access token permits. During the access-token request, your application sends one or more values in the scope parameter.
see https://developers.google.com/identity/protocols/OAuth2
The withCredentials option is set, in order to create a cookie, to pass the authentication token, to the REST server.
Finally this resource may help you https://hackernoon.com/adding-oauth2-to-mobile-android-and-ios-clients-using-the-appauth-sdk-f8562f90ecff

How to prioritize the reponse over request in ASP.NET Web Api

I have a code that looks something like this:
class SomeController {
HttpClient client = new HttpClient();
public Task<dynamic> SomeAction() {
Task.Run<dynamic>(() => {
var response = client.GetAsync(new Uri(someUrl));
return response.ReadAsAsync<dynamic>().Result;
});
}
}
Now, I call this api with many requests (around 300) and the 'someUrl' returns the response after about 200ms.
After adding some console logs I can see a behavior:
All the 200 requests arrive and request the someUrl resource
The first 2-3 requests to someUrl are handled and returned properly
Other responses are waiting for all the 300 requests to arrive and only then they are returned back...
I have heard that there is no prioritization of responses over incoming requests in situations like these but it seems weird to me. It seems like the requests coming to my server and the responses that are coming from the someUrl are on the same queue and until all the requests are sent no response can be handled.
Anyone else encountered this situation? Anyone knows how to handle it properly?
Thanks!

Can Ajax make a Cross-Origin Login?

I'm trying to login from one of my servers to another in order to send cross-origin requests that requires being logged. is it possible?
I have two web servers, A and B. Lets say www.a.com and www.b.com.
B has an API that can be used only if the client is logged in. I need to use that API from A clients.
So, I send from A client an ajax (post) login request to B. B responses with CORS headers, the session cookie and a successful redirection to B's home/index.
But when I make a second ajax request (jsonp request) from A client to B server, this request doesn't send the previous session cookie received, therefore the login request failed.
If I login to www.b.com manually (in a second browser tab), all requests from A to B are successful detected as a logged user, so, the B API works from A.
I think that the session cookie received from my login requests is not being saved to the browser.
This is my login request:
$.post("www.b.com/login", { 'j_username': 'username', 'j_password': 'password' } );
Using:
jqXHR.withCredentials = true;
settings.crossDomain = true;
Response headers:
Access-Control-Allow-Headers:x-requested-with
Access-Control-Allow-Methods:POST, GET, OPTIONS
Access-Control-Allow-Origin:*
...
Location:http://www.b.com/home
...
Set-Cookie:JSESSIONID=tY++VWlMSxTTUkjvyaRelZ0o; Path=/
The cookie received is being saved to www.a.com or to www.b.com? How can I set this cookie to www.b.com from an A client ajax request? I think that is the problem.
As apsillers said, we can't use the wildcard Access-Control-Allow-Origin:*.
But this doesn't solved the problem.
I was setting jqXHR.withCredentials = true; inside a beforeSend handler function.
$.post({
...
beforeSend: function(xhr) {
xhr.withCredentials = true;
},
...
});
And for some reason, this doesn't work. I had to set the use of credentials directly:
$.post({
...
xhrFields: {
withCredentials: true
},
...
});
This code works perfectly !
Thanks you.

How to get GPS data from Waze with rest-client?

I'm trying to get my GPS data from the Waze app using the rest-client lib. I'm basicly trying to fake a login via the website https://www.waze.com/. After login (you can use JohnDoeSpeedy228:gre#tStory92) when you visit https://www.waze.com/editor/, click on "Drives" after review the the network calls you'll get to see the raw JSON data.
I seem to have succesfully logged in but when making the request to return the list of all my drives it returns the following
{"users"=>{"objects"=>[]}, "archives"=>{"totalSessions"=>0, "objects"=>[]}}
It should return something like this:
{
"users":{
"objects":[
]
},
"archives":{
"totalSessions":1,
"objects":[
{
"id":<REDACTED>,
"userID":<REDACTED>,
"existingRoadMeters":2839,
"newRoadMeters":0,
"totalRoadMeters":2839,
"startTime":1456996197000,
"endTime":1456996636000,
"hasFullSession":true
}
]
}
}
Here's what I'm trying:
require 'rest-client'
require 'json'
GET_CSRF_URL = "https://www.waze.com/login/get"
SESSION_URL = "https://www.waze.com/login/create"
SESSION_LIST_URL = "https://www.waze.com/Descartes-live/app/Archive/List"
SESSON_DATA_URL = "https://www.waze.com/Descartes-live/app/Archive/Session"
AUTH = {'user_id'=>'JohnDoeSpeedy228','password'=>'gre#tStory92'}
req = RestClient.get(GET_CSRF_URL)
csrfhash = req.cookies
csrfhash['editor_env'] = 'row'
headers = {'X-CSRF-Token'=>csrfhash['_csrf_token']}
log = RestClient::Request.execute(
method: :post,
url: SESSION_URL,
cookies: csrfhash,
headers: headers,
payload: AUTH
)
ses = RestClient::Request.execute(
method: :get,
url: SESSION_LIST_URL,
cookies: log.cookies,
payload: {'minDistance'=>1000,'count'=>50, 'offset'=>0}
)
puts JSON.parse(ses)
Am I doing something wrong?
My guess is that you are confusing two accounts. Are you sure you logged a drive while logged in as JohnDoeSpeedy228? If there are no sessions from that user when logged into the site manually, I wouldn't expect the code to work either.
We can't find any of your drives.
Have you started driving with the Waze app yet? If so, please make sure you logged into the Map Editor with the same credentials you use in the app.

SailsJS - using sails.io.js with JWT

I have implemented an AngularJS app, communicating with Sails backend through websockets, using sails.io.js.
Since the backend is basically a pure API and will be connected to from other apps as well, I'm trying to disable sessions completely and use JWT.
I have set up express-jwt and can use regular HTTP requests quite nicely, but when I send a request through sails.io.js, nothing happens at all - websocket request keeps pending on the client, and there's nothing happening on the server (with "silly" log level).
I've tried patching sails.io.js to support the query parameter, and when connecting, I send the token from Angular, but in the best case, I get a response with error message coming from express-jwt saying credentials are missing...
I've also seen some hints that socket.js in sails needs to be modified with beforeConnect, I've seen socketio-jwt, but have no idea where and how to plug that in, in Sails.
Has anyone implemented this and is using JWT with Sails and sockets? I'd appreciate any kind of hint in what direction to go :)
I realised that policy I've put in place and that was using express-jwt abstracted too much away from me, so I didn't figure out what exactly was happening. Once I looked at other examples, I've figured out that I only needed to check what's different for websocket requests than regular, and I quickly found a way around the problem.
So:
set up token signing and sending on login
Angular takes the token and saves to local storage
Create an interceptor for HTTP requests to add authorization header and token
Fix up sails.io.js to forward query parameters provided through options (as mentioned in the question)
When connecting using sails.io.js, send token as query parameter, i.e. url + '?token=' + token
In sails policy, check all combinations for token, including req.socket.handshake.query, as below:
module.exports = function (req, res, next) {
var token;
if (req.headers && req.headers.authorization) {
var parts = req.headers.authorization.split(' ');
if (parts.length == 2) {
var scheme = parts[0],
credentials = parts[1];
if (/^Bearer$/i.test(scheme)) {
token = credentials;
}
} else {
return res.json(401, {err: 'Format is Authorization: Bearer [token]'});
}
} else if (req.param('token')) {
token = req.param('token');
// We delete the token from param to not mess with blueprints
delete req.query.token;
}
// If connection from socket
else if (req.socket && req.socket.handshake && req.socket.handshake.query && req.socket.handshake.query.token) {
token = req.socket.handshake.query.token;
} else {
sails.log(req.socket.handshake);
return res.json(401, {err: 'No Authorization header was found'});
}
JWTService.verifyToken(token, function (err, token) {
if (err) {
return res.json(401, {err: 'The token is not valid'});
}
sails.log('Token valid');
req.token = token;
return next();
});
};
It works well! :)

Resources