Dart HttpClient with Basic Authentication issues after flutter upgrade - dart

After a lot of browsing and reading docs, I came across this answer, which worked until I upgraded flutter.
My current issue is that the credentials do not reach my server.
IntelliJ error:
I/FlutterActivityDelegate( 6944): onResume setting current activity to this
D/EGL_emulation( 6944): eglMakeCurrent: 0xa7f852a0: ver 2 0 (tinfo 0xa7f83250)
I/flutter ( 6944): doing login with credentials:: W and T
I/flutter ( 6944): my_response is:: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
I/flutter ( 6944): <title>429 Too Many Requests</title>
I/flutter ( 6944): <h1>Too Many Requests</h1>
I/flutter ( 6944): <p>1 per 1 minute</p>
E/flutter ( 6944): [ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
E/flutter ( 6944): type '(Exception) => void' is not a subtype of type '(Object) => FutureOr<dynamic>'
My server output for the request is:
credentials:: -
192.168.1.175 - - [12/May/2018 10:56:23] "GET /users/login HTTP/1.1" 401 -
192.168.1.175 - - [12/May/2018 10:56:23] "GET /users/login HTTP/1.1" 429 -
LE: the "credentials:: - " is a print done in the authentication level of the server.
LLE: a curl request is working just fine
curl -u 123456:password http://localhost:5000/users/login
{
"is_logged_in": true,
"last_login": 1525980360
}
Response is:
credentials:: 123456 - password
127.0.0.1 - - [12/May/2018 13:00:50] "GET /users/login HTTP/1.1" 200 -
I am using the exact same code as in the link provided above.

Here's a summary answer wrapping up the discussion in the comments.
It seems like the Too Many Requests error may have been triggered by the typical behaviour of HTTP client talking to server that requires authorization.
GET ->
<- 401 Unauthorized + scheme + realm (and nonce if applicable)
GET with Authorization header ->
<- 200 OK (if credentials are valid)
It seems like the server may have counted the first GET/401 towards some sort of limit of requests per minute.
However, a request from curl was successful, probably because curl preemptively sent the Authorization header with the first GET, instead of waiting to be asked with a 401. It can do this as long as the authorization scheme is Basic because it doesn't need any information from the server. (It wouldn't work with Digest because it cannot calculate the Authorization header without the nonce sent with the 401.)
So the question arises, is there a way to preemptively send Basic auth in package:http?
Normal way - only send in response to a 401
// create an IOClient with authentication
HttpClient inner = new HttpClient();
inner.authenticate = (uri, scheme, realm) {
inner.addCredentials(
uri, realm, new HttpClientBasicCredentials(username, password));
};
http.IOClient client = new http.IOClient(inner);
// and use it like this
http.Response response = await client.get('https://api.somewhere.io');
// todo - handle the response
Preemptive way - only works with Basic authentication
// use the normal http.get method, but add the header manually, with every request
http.Response response = await http.get(
'https://api.somewhere.io',
headers: {'authorization': basicAuthenticationHeader(username, password)},
);
// todo - handle the response
with the utility method
String basicAuthenticationHeader(String username, String password) {
return 'Basic ' + base64Encode(utf8.encode('$username:$password'));
}

Related

RestAssured - how to send a request without Content-Type?

I am using RestAssured to send a request:
Map<String, Object> headers = new HashMap<>();
headers.put("Accept", "*/*");
headers.put("Accept-Encoding", "gzip, deflate, br");
headers.put("Connection", "keep-alive");
Response response = RestAssured.given().baseUri(BASE_URL)
.headers(headers)
.log().all()
.post(URL_PREFIX + "/documents/request/" + username);
However, in the log I see that 1 more header was automatically added:
Content-Type=application/x-www-form-urlencoded; charset=ISO-8859-1
And I get 415 error.
Is it possible to send a request without Content-Type? I mean, without this header at all; if the request is sent with Content-Type equal to empty line, there is still a 400 error; the only way to make it work is to send the request without this header.
Seems like there is a bug in the RestAssured framework that is still open (I verified that in 4.3.3).
// https://mvnrepository.com/artifact/io.rest-assured/rest-assured
testImplementation group: 'io.rest-assured', name: 'rest-assured', version: '4.3.3'
Founded out, when creating negative tests for a API. Content type below is automatically generated when trying to send request.
Content-Type=application/x-www-form-urlencoded; charset=ISO-8859-1
Bug defined here:
https://github.com/rest-assured/rest-assured/issues/656
https://github.com/rest-assured/rest-assured/issues/986

Auth0 OAuth2.0 redirect 500

Is it ever expected to see a "500" status response during the final redirect from an OAuth2 provider?
server_error: Unable to issue redirect for OAuth 2.0 transaction
I'm trying to determine if this is ultimately the provider Auth0's error (it seems to be) or mine. If it were mine I'd expect a 400 series error. It is possible to have hooks or rules, could these result in 500-series errors in a scenario like this? I would also anticipate a more specific 500-error not 500 but another available number like 599 for lack of a better example.
My more specific case has something like:
new auth0.WebAuth({
domain: '....auth0.com'
,clientID: 'theid...'
,callbackUri: 'http://localhost:8080/'
,audience: 'http...',
,responseType: 'token id_token'
,scope: 'openid profile'
,leeway: 60
});
success then 500 for /login/callback?state=... on return
I misspelled the callback field, it should be redirectUri (not callbackUri above)! Auth0 tech support was kind enough to point this out.
I also asked about changing the error from 500 internal server error to 400 "Bad Request" to indicate a missing client-provided detail per my read of the details
https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
details for 400 (and the rest) https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1

Handling non-Ok requests in dart

I have this simple dart snippet:
import 'package:http/http.dart' as http;
Client _http = new BrowserClient();
final response = await _http
.post(url, headers: someHeader, body: someValue);
The server for the current request, returns Bad Request 400 response. I want to be able to get the status code for some reasons. But as soon as the _http.post get called, I get this error:
POST http://localhost/path 400 (Bad Request)
Putting the block in try/catch doesn't help, since the exception catched is ClientException which has no information about status-code and response-body (which is important here). How can I handle status-codes here, without throwing exceptions?
UPDATE:
I have this snippet after _http.post() call:
if (response.statusCode == 400) {
// manage bad request
}
But the response is null, so the statusCode is not accessible here.
UPDATE 2:
I get the request on server and can trace on server. As I mentioned, the server is sending a 400 Bad Request response, and works just fine. But getting the response in Dart causes the error.
The Response object has a field statusCode where you can get the status code of the response.
You can do something like that:
final response = await _http
.post(url, headers: someHeader, body: someValue);
if (response.statusCode == 400) {
// manage bad request
}
I suspect the url, a header or the body is invalid somehow. (e.g. invalid characters in a header). The request is not actually being sent to the server, and so ClientException is being thrown instead of giving you a response.

Google Oauth 2.0 authentication for limited input device not working except on curl

I am trying to use a custom java application of mine to upload videos to my youtube account via an access limited device like a Raspberry pi running as a server.
For this I am using the Google Oauth 2.0 for limited input device as a reference.
I followed the steps mentioned with my custom java application, Fiddler and curl, the surprise is as follows:
All of the calls worked right as mentioned by Google Oauth 2.0 for limited input device for curl.
But issues were observed with Fiddler and my custom java app for the following call:
When I am trying to get the access token from Google server (Step 4 from Google Oauth link) by posting similar request:
POST /o/oauth2/token HTTP/1.1
Host: accounts.google.com
Content-Type: application/x-www-form-urlencoded
client_id=1084945748469-eg34imk572gdhu83gj5p0an9fut6urp5.apps.googleusercontent.com&
client_secret=hDBmMRhz7eJRsM9Z2q1oFBSem&
code=4/YMSlR3fSCC1NtUh073DuZKTJJ3ss&
grant_type=http://oauth.net/grant_type/device/1.0
but instead of getting the 'access_token' as response I am getting the following :
Status Code:400 Response: { "error" : "invalid_request",
"error_description" : "Required parameter is missing: grant_type" }
Note : With or without url encoding, my problem stays the same.
I am unable to understand what the issue is with my custom java app or with fiddler, Please help.
Following are my fiddler requests:
(One can get oauth credentials (client_id and client_secret) by following this)
Fiddler request:
(url encoded, obscured client secret)
POST HTTP/1.1
https://accounts.google.com/o/oauth2/token?client_id=308065994473-ur9dd7003ajs6mvr5s4kqnugr6j8tsf2.apps.googleusercontent.com&client_secret=XXXXXXXXXXXXXXX&code=4%2FWR-qiTquqB0e4-0LCy0-7rZ2kkE2&grant_type=http%3A%2F%2Foauth.net%2Fgrant_type%2Fdevice%2F1.0
Content-Type: application/x-www-form-urlencoded
(non url encoded, obscured client secret)
POST HTTP/1.1
https://accounts.google.com/o/oauth2/token?client_id=308065994473-ur9dd7003ajs6mvr5s4kqnugr6j8tsf2.apps.googleusercontent.com&client_secret=XXXXXXXXXXXXXX&code=4/WR-qiTquqB0e4-0LCy0-7rZ2kkE2&grant_type=http://oauth.net/grant_type/device/1.0
Java code project is available at (maven project, check the test case for the Oauth calls):
https://docs.google.com/file/d/0B8ltWBtPF-DVMDZFNHNMZXpCQlk
The parameters need to be added in the http post request body not in the url, Google documentation is confusing on this part.
public synchronized HttpResponse executePOST(HttpEntity httpEntity, String path) throws IOException {
if (!parameters.isEmpty()) {
httpPost.setEntity(new UrlEncodedFormEntity(parameters));
}
httpPost = new HttpPost(path);
logger.info(target.toHostString());
logger.info(httpPost.getURI().toString());
logger.info(httpPost.getRequestLine().toString());
for (Header header : headers) {
logger.info(header.getName() + ": " + header.getValue());
httpPost.addHeader(header);
}
httpResponse = httpClient.execute(target, httpPost);
return httpResponse;
}

Bad request on ProcessUserAuthorization (DotNetOpenAuth 4.2.2.13055)

I'm trying to upgrade the DotNetOpenAuth verson to 4.2.2.13055, in the Google dotnet client library.
So I downloaded the latest dlls - DotNetOpenAuth.Core, DotNetOpenAuth.OAuth2, etc. (we still don't work with NuGet).
I made a small change (changed the way I construct NativeApplcationClient with client_id and client_secret) to support the new version.
Then, I tried to run a sample we have in our samples repository (e.g. https://code.google.com/p/google-api-dotnet-client/source/browse/Tasks.SimpleOAuth2/Program.cs?repo=samples), and I got a bad request error, as following:
DotNetOpenAuth.Messaging.ProtocolException: Error occurred while sending a direct message or getting the response. --->
System.Net.WebException: The remote server returned an error: (400) Bad Request.
at System.Net.HttpWebRequest.GetResponse()
at DotNetOpenAuth.Messaging.StandardWebRequestHandler.GetResponse(HttpWebRequest request, DirectWebRequestOptions opt
ions)
--- End of inner exception stack trace ---
at DotNetOpenAuth.Messaging.StandardWebRequestHandler.GetResponse(HttpWebRequest request, DirectWebRequestOptions opt
ions)
at DotNetOpenAuth.Messaging.StandardWebRequestHandler.GetResponse(HttpWebRequest request)
at DotNetOpenAuth.Messaging.Channel.GetDirectResponse(HttpWebRequest webRequest)
at DotNetOpenAuth.Messaging.Channel.RequestCore(IDirectedProtocolMessage request)
at DotNetOpenAuth.Messaging.Channel.Request(IDirectedProtocolMessage requestMessage)
at DotNetOpenAuth.OAuth2.ClientBase.UpdateAuthorizationWithResponse(IAuthorizationState authorizationState, EndUserAu
thorizationSuccessAuthCodeResponse authorizationSuccess)
at DotNetOpenAuth.OAuth2.UserAgentClient.ProcessUserAuthorization(IAuthorizationState authorizationState, IDirectedPr
otocolMessage response)
at DotNetOpenAuth.OAuth2.UserAgentClient.ProcessUserAuthorization(Uri actualRedirectUrl, IAuthorizationState authoriz
ationState)
at Google.Apis.Authentication.OAuth2.DotNetOpenAuth.NativeApplicationClient.ProcessUserAuthorization(String authCode,
IAuthorizationState authorizationState) in c:\code.google.com\google-api-dotnet-client\default_oauth2\Src\GoogleApis.Au
thentication.OAuth2\DotNetOpenAuth\NativeApplicationClient.cs:line 102
at Google.Apis.Samples.TasksOAuth2.Program.GetAuthorization(NativeApplicationClient arg) in c:\code.google.com\google
-api-dotnet-client\samples_oauth2\Tasks.SimpleOAuth2\Program.cs:line 73
at Google.Apis.Authentication.OAuth2.OAuth2Authenticator`1.LoadAccessToken() in c:\code.google.com\google-api-dotnet-
client\default_oauth2\Src\GoogleApis.Authentication.OAuth2\OAuth2Authenticator.cs:line 124
I noticed also that there is a different in the second request (in exchanging the code with a token): Authorization header was added to the request, and the body was missing my client_id and client_secret.
Similar code worked on old version - 4.0.0.11165,
Am I missing something?
I wonder if the problem is that the newer DNOA version supports putting client credentials in the HTTP header by default. If you create your Client class, passing in a different client credential provider into the constructor, it may work for you.
To change the behavior from using the HTTP Authorization header back to passing client credentials in the POST entity, instantiate your ClientBase-derived class passing in this as a parameter to the constructor:
ClientCredentialApplicator.PostParameter(clientSecret)

Resources