I'm currently making a web application to control a Lumens LC101. When I login to the device I get a session id, which I use to call commands, for authorization. But when I call a command - for example keepalive - and posted the session with it, Lumens gives me an authorization error code: -14.
This is how I post the session and call a command:
ServicePointManager.Expect100Continue = false;
// Create HttpWebRequest
var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://192.168.0.103/api/keepalive");
httpWebRequest.ContentType = "text/json";
httpWebRequest.Method = "POST";
// Post json data
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream())) {
streamWriter.Write("{\"session\":\"" + session + "\"}");
streamWriter.Flush();
streamWriter.Close();
}
// Get response of HttpWebRequest
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
// Read stream from response
using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) {
string result = streamReader.ReadToEnd();
JObject jsonResult = JObject.Parse(result);
int code = Int32.Parse(jsonResult.GetValue("code").ToString());
// Return result
if (code >= 0) return result;
int code will be -14 in this case, because authorization failed. But I'm using the same session id, which I got from the login.
How do I make sure it won't give me an authorization error code: -14?
EDIT
This is how it's described in the documentation:
Here's the documentation. Session is described in paragraph 1.2
Related
Hi I am Calling External Rest API, I have Get Correct Results of GET and One POST API Result But this gives the error: The remote server returned an error: (400) Bad Request . But in POSTMAN it is working fine.
In Postman I am Calling http://192.168.x.x:8088/ari/channels/100001.100/play?media=sound:hello-world&api_key=admin:admin&app=myapp1 .
My Code is below and I passing Parameters and query string in API.
I think my problem is in media = sound:hello-world but I have no idea to solve.
string url = String.Format("http://192.168.x.x:8088/ari/channels/play?api_key=admin:admin");
WebRequest requestPost = WebRequest.Create(url);
requestPost.Method = "POST";
requestPost.ContentType = "application/json";
string postData = "{\"channelId\":\"100001.100\",\"media=sound\":\"hello-world\",\"app\":\"myapp1\"}";
using (var streamWriter = new StreamWriter(requestPost.GetRequestStream()))
{
streamWriter.Write(postData);
streamWriter.Flush();
streamWriter.Close();
}
var httpResponse = requestPost.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var res = streamReader.ReadToEnd();
}
I want to get from Jenkins the last build status via C# code, once I'm triggered a "GET" request it returns me 403 forbidden.
public void GetJsonByGet(string url)
{
string json = string.Empty;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("JenkinsEndPoint");
request.Credentials = new NetworkCredential("User","Password"); //CredentialCache.DefaultCredentials;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
json = reader.ReadToEnd();
}
}
Check your jenkins has csrf activated or not. if it does you have to implement a call to get the csrf token and use this token for your next requests
I am developing a C# application which needs to use the onelogin API to retrieve a session token. I am able to authenticate and and create a token with the following code:
WebRequest Authrequest = WebRequest.Create("https://api.us.onelogin.com/auth/oauth2/token");
Authrequest.Method = "POST";
Authrequest.ContentType = "application/json";
Authrequest.Headers.Add("cache-control", "no-cache");
Authrequest.Headers.Add("Authorization: client_id:XXXXXXX7bbf2c50200d8175206f664dc28ffd3ec66eef0bfedb68c3366420dc, client_secret:XXXXXXXXXX6ba2802187feb23f6450c6812b8e6639361d24aa83f12010f ");
using (var streamWriter = new StreamWriter(Authrequest.GetRequestStream()))
{
string Authjson = new JavaScriptSerializer().Serialize(new
{
grant_type = "client_credentials"
});
streamWriter.Write(Authjson);
}
WebResponse AuthReponse;
AuthReponse = Authrequest.GetResponse();
Stream receiveStream = AuthReponse.GetResponseStream ();
// Pipes the stream to a higher level stream reader with the required encoding format.
StreamReader readStream = new StreamReader (receiveStream);
JObject incdata = JObject.Parse(readStream.ReadToEnd());
string sToken = incdata["data"][0]["access_token"].Value<string>();
AuthReponse.Close();
However, when running the Create Session Login Token with the following code, it only returns a 400 error, and the message has no detail. Just Bad Request:
//Get the session token for the specified user, using the token recieved from previous web request
WebRequest request = WebRequest.Create("https://api.us.onelogin.com/api/1/login/auth");
request.Method = "POST";
request.ContentType = "application/json";
request.Headers.Add("authorization", "bearer:" + sToken);
using (var streamWriter2 = new StreamWriter(request.GetRequestStream()))
{
string json = JsonConvert.SerializeObject(new
{
username_or_email = sUsername,
password = sPassword,
subdomain = "comp-alt-dev"
});
streamWriter2.Write(json);
}
WebResponse response;
response = request.GetResponse();
string streamText = "";
var responseStream = response.GetResponseStream();
using (responseStream)
{
var streamReader = new StreamReader(responseStream);
using (streamReader)
{
streamText = streamReader.ReadToEnd();
streamReader.Close();
//
}
responseStream.Close();
}
Any ideas?
-Thank you
Also for anyone who may be getting this error. in C# the email is case sensitive. I tried User.email.com. In onelogin it was saved as user#email.com. changing the c# to lower case fixed it.
Can you let us know what payload you're sending across the wire to the .../1/login/auth endpoint as well as the response (either as others have suggested as packet snoop, or just as a debug output from the code)
400 means either bad json or the endpoint requires MFA, so this will narrow it down.
~thanks!
Just joining the troubleshooting effort =) -- I can replicate a 400 Bad Request status code with a "bad request" message when the request body contains a username_or_email and/or subdomain value that does not exist, or if the request body is empty.
Can you post what goes over the wire to the OneLogin endpoint...
OK Thanks. So it appears your subdomain does not exist. If you give me an email in the account I can find the correct subdomain value for you.
I am using Stormpath for my authentication service. I call the RestAPI of Stormpath by using HttpWebRequest.
I am also using HttpWebRequest to call the RestAPI but it does not work.
private void BtnGetResetApiClick(object sender, EventArgs e)
{
var username = "aaaa";
var password = "bbbb";
ServicePointManager.ServerCertificateValidationCallback = Callback;
var request = WebRequest.Create("https://api.stormpath.com/v1/tenants/current") as HttpWebRequest;
request.UserAgent = ".NET SDK";
request.Method = "GET";
request.Accept = "*/*";
var data = string.Format("{0}:{1}", username, HttpUtility.HtmlEncode(password));
var token = Convert.ToBase64String(Encoding.UTF8.GetBytes(data));
string authHeader = string.Format("Basic {0}", token);
request.Headers.Add("Authorization", authHeader);
request.ServerCertificateValidationCallback = Callback;
using (var response = request.GetResponse())
{
var stream = response.GetResponseStream();
if (stream != null)
{
var streamReader = new StreamReader(stream);
var str = streamReader.ReadToEnd();
streamReader.Close();
stream.Close();
}
}
}
private bool Callback(object obj, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{
return true;
}
When calling:
var response = request.GetResponse()
I got an exception:
An unhandled exception of type 'System.Net.WebException' occurred in System.dll The remote server returned an error: (401) Unauthorized.
Can you help me to see if my code has something wrong?
Update - use the SDK, it's much easier!
If you're calling the Stormpath API from C# frequently, don't bother with writing requests by hand. Use the Stormpath .NET SDK instead. I'm the author. :)
Install it using install-package Stormpath.SDK from the Package Manager Console. Then, create an IClient object:
// In a production environment, you'll want to load these from
// environment variables or a secure file, instead of hardcoding!
var apiKey = ClientApiKeys.Builder()
.SetId("Your_Stormpath_API_key_ID")
.SetSecret("Your_Stormpath_API_key_secret")
.Build();
var client = Clients.Builder()
.SetApiKey(apiKey)
.Build();
Getting the tenant info is now just a simple call:
var tenant = await client.GetCurrentTenantAsync();
Console.WriteLine($"Current tenant is: {tenant.Name}");
If you really want to make raw requests, you can still do that! I'll explain below.
Constructing the Authorization header
A 401 Unauthorized response means that the API was not able to find a valid Authorization header in your request. To authenticate correctly, you need two things:
An authorization payload in the format apiKeyID:apiKeySecret
An Authorization header with value: Basic base64(payload)
Here's how to construct the complete header:
// API_KEY_ID and API_KEY_SECRET populated elsewhere
var authPayload = string.Format("{0}:{1}", API_KEY_ID, API_KEY_SECRET);
var authPayloadEncoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(authPayload));
request.Headers.Add(HttpRequestHeader.Authorization, "Basic " + authPayloadEncoded);
You don't need the ServerCertificateValidationCallback = Callback stuff. With the above header, the request will be seen by the API as a valid request (assuming your API Key ID and Secret are correct, of course).
Redirection handling
One thing to watch out for (this tripped me up at first!) is that WebRequest will follow HTTP 302 redirects automatically, but will not apply the existing headers to the new request.
The solution is to disable redirect following:
request.AllowAutoRedirect = false;
This means you'll have to handle 302 responses yourself, but it's the only way to correctly apply the Authorization header to each request.
Working example
I created a simple working example in this gist. Since I'll be creating requests multiple times, I wrote a helper function:
private static HttpWebRequest BuildRequest(string method, string uri)
{
var request = WebRequest.Create(uri) as HttpWebRequest;
request.UserAgent = "dotnet/csharp web-request";
request.Method = method;
request.ContentType = "application/json";
// Important, otherwise the WebRequest will try to auto-follow
// 302 redirects without applying the authorization header to the
// subsequent requests.
request.AllowAutoRedirect = false;
// Construct HTTP Basic authorization header
var authPayload = string.Format("{0}:{1}", API_KEY_ID, API_KEY_SECRET);
var authPayloadEncoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(authPayload));
request.Headers.Add(HttpRequestHeader.Authorization, "Basic " + authPayloadEncoded);
return request;
}
And a simple console app to demonstrate getting the current tenant URL and name:
// Get these from the Stormpath admin console
private static string API_KEY_ID = "Your_Stormpath_API_key_ID";
private static string API_KEY_SECRET = "Your_Stormpath_API_key_secret";
static void Main(string[] args)
{
// First, we need to get the current tenant's actual URL
string tenantUrl = null;
var getCurrentTenantRequest = BuildRequest("GET", "https://api.stormpath.com/v1/tenants/current");
try
{
using (var response = getCurrentTenantRequest.GetResponse())
{
tenantUrl = response.Headers["Location"];
}
}
catch (WebException wex)
{
Console.WriteLine("Request failed. {0}", wex.Message);
throw;
}
// Now that we have the real tenant URL, get the tenant info
string tenantData = null;
var getTenantInfoRequest = BuildRequest("GET", tenantUrl);
try
{
using (var response = getTenantInfoRequest.GetResponse())
using (var responseStream = response.GetResponseStream())
using (var reader = new StreamReader(responseStream))
{
tenantData = reader.ReadToEnd();
}
}
catch (WebException wex)
{
Console.WriteLine("Request failed. {0}", wex.Message);
throw;
}
// Use JSON.NET to parse the data and get the tenant name
var parsedData = JsonConvert.DeserializeObject<Dictionary<string, object>>(tenantData);
Console.WriteLine("Current tenant is: {0}", parsedData["name"]);
// Wait for user input
Console.ReadKey(false);
}
The code is pretty verbose because we're making raw requests to the API. Again, if you're making requests frequently, use the SDK instead!
I am not getting the results that documentation says. I login the Buddy; created application; copy this URL and assign to url string; when I execute the program I am not getting results that are expected (status + Accesstoken) as documentation says. Can anyone please tell me if I am missing something as newbie to http calls. Its running on http requester but not on Poster firefox add-on!
Documentation
http://dev.buddyplatform.com/Home/Docs/Getting%20Started%20-%20REST/HTTP?
Code
string parameters = "{appid:'xxxxxx', appkey: 'xxxxxxx', platform: 'REST Client'}";
private async void SimpleRequest()
{
HttpWebRequest request = null;
HttpWebResponse response = null;
try
{
request = (HttpWebRequest)WebRequest.Create(url);
request.Accept = "application/json";
request.ContentType = "application/json";
request.Method = "POST";
StreamWriter sw = new StreamWriter(await request.GetRequestStreamAsync());
sw.WriteLine(parameters);
sw.Close();
response = (HttpWebResponse) await request.GetResponseAsync();
}
catch (Exception)
{ }
}
Using the HTTP requester add-on on Firefox, I successfully retrieved an access token so their API work.
In C# they provide a line of code to submit your appid and appkey, that might be the problem :
Buddy.Init("yourAppId", "yourAppKey");
My guess is you have to use their .NET SDK!
You can certainly use the REST API from raw REST the way you're doing, though the .NET SDK will handle some of the more complex details of changing service root. I ran your code using my own Buddy credentials and I was able to get JSON containing an Access Token back. You may need to read the response stream back as JSON to retrieve the access token. I used the following code to dump the JSON to the console:
request = (HttpWebRequest)WebRequest.Create(url);
request.Accept = "application/json";
request.ContentType = "application/json";
request.Method = "POST";
StreamWriter sw = new StreamWriter(await request.GetRequestStreamAsync());
sw.WriteLine(parameters);
sw.Close();
response = (HttpWebResponse)await request.GetResponseAsync();
Console.WriteLine(await new StreamReader(response.GetResponseStream()).ReadToEndAsync());
Using Newtonsoft.Json I can parse out my accessToken like this:
Uri url = new Uri("https://api.buddyplatform.com/devices");
request = (HttpWebRequest)WebRequest.Create(url);
request.Accept = "application/json";
request.ContentType = "application/json";
request.Method = "POST";
StreamWriter sw = new StreamWriter(await request.GetRequestStreamAsync());
sw.WriteLine(parameters);
sw.Close();
response = (HttpWebResponse)await request.GetResponseAsync();
var parsed = JsonConvert.DeserializeObject<IDictionary<string,object>>( (await new StreamReader(response.GetResponseStream()).ReadToEndAsync()));
var accessToken = (parsed["result"] as JObject).GetValue("accessToken").ToString();
Console.WriteLine(accessToken);
The 3.0 SDK does all of this for you while exposing the rest of the service through a thin REST wrapper, the migration guide for the 3.0 SDK should help with this.