Hue API remote Basic Authentication - node.js

I'm having issues using the Basic Authentication method for the Hue remote API.
When POSTing to https://api.meethue.com/oauth2/token?code={code}&grant_type=authorization_code with the built Authorization-header I get this response:
{
"fault": {
"faultstring": "Invalid client identifier {0}",
"detail": {
"errorcode": "oauth.v2.InvalidClientIdentifier"
}
}
}
I assume then that I am building the token in the wrong way, but the docs (see Basic Authentication) is a bit vague on what to actually do.
The docs says that I should send a header via this format: Authorization: Basic <base64(clientid:clientsecret)> and that it should be encoded in base-64:
you would need to send a Basic authorization header that includes a base64 encrypted hash of your clientid and clientsecret.
And from the Digest-method, I assume MD5 is used and then digested to base-64.
Here's what I've tried, all with the same error-code:
'Basic ' + crypto.createHash('md5').update(clientId + clientSecret).digest('base64')
'Basic ' + crypto.createHash('md5').update(clientId + ':' + clientSecret).digest('base64')
'Basic ' + (clientId + ':' + clientSecret).toString('base64')
'Basic ' + (clientId + clientSecret).toString('base64')
What more is there to try?

#Tokfrans
you can create a test token with clientid:secret by using the site
https://www.base64encode.org/
it will give you a valid token that you can use with Basic authentication
keep in mind that you first need to get a code which you can then use to get a accesstoken
https://api.meethue.com/oauth2/auth?clientid=xxxxxx&appid=xxxxx&deviceid=xxxx&devicename=xxxx&state=xxxx&response_type=code

Related

How to get access token from Azure Active Directory with certificate when service is behind proxy

I need to create service that calls graph api to access company data. In order to authenticate I need JWT token from Azure Active Directory. The authentication will be using application mode with signing certificate. I tried to use MSAL node ConfidentialClientApplication but the service needs to use http proxy to connect to internet. To my knowledge MSAL node does not support this and calls result in library being unable to resolve the address of "https://login.microsoftonline.com". How can I make MSAL node use the proxy or get JWT token without use od MSAL?
In order to get JWT token from azure active directory without MSAL node, one have to generate proper JWT token on its own and then sign it with certificate private key. The header of the token consists of following fields:
{
typ: "JWT",
alg: "RS256",
kid: "156E...",
x5t: "iTYVn..."
}
"kid" is the thumbprint of the certificate used to sign the request - here is a good example how to obtain it for pfx file with powershell https://stackoverflow.com/a/32980899/3588432
"x5t" is base64 encoded and sanitized certificate thumbprint.
Sanitization of base64 encoded string means:
trimming "=" signs at the end
replace "/" with "_"
replace "+" with "-"
Exemplary C# code for the sanitization:
var sanitized = s.Split('=')[0].Replace('+', '-').Replace('/', '_');
and JS code:
var sanitized = s.split('=')[0].replace('+', '-').replace('/', '_');
The payload of the token consists of the following fields:
{
aud: "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token",
iss: "{clientId}",
nbf: 1617952610,
exp: 1617953210,
sub: "{clientId}",
jti: "e13efcf..."
}
{tenantId} and {clientId} are Azure AD data of application we are authenticating to
"nbf" is the time when the token will began to be valid, normally it is time the token got generated. It has unix epoch format https://en.wikipedia.org/wiki/Unix_time and is an integer.
"exp" - the time the token expires in unix epoch format.
"jti" - a unique token identifier. It may be random generated guid. Should be different for every request.
An example how to get "nbf" value in JavaScript:
var nbf = Math.floor(new Date().getTime() / 1000);
When ready header and payload should be serialized (with sanitization) on concatenated with ".":
var token = JSON.stringify(header) + "." + JSON.stringify(payload);
Then we need to sign it with certificate private key, encode it with base 64 (with sanitization) and prepare a clientAssertion value:
var clientAssertion = token + "." + signedToken;
As a last step can send request to get JWT token:
const body = new URLSearchParams();
const token = await fetch("https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token", {
agent: new HttpsProxyAgent("http://..."),
body: new URLSearchParams({
"client_assertion": clientAssertion,
"client_id": "{clientId}",
"scope": "https://graph.microsoft.com/.default"
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
"grant_type": "client_credentials"
}),
method: "POST",
headers: {
"content-type": "application/x-www-form-urlencoded"
}
})
.then(response => response.json().access_token);

Invalid Base64 SAML Assertion from OAuth on-behalf-of flow in Azure AD

I am experiencing a weird issue when exchanging a OAuth access token to a SAML Assertion using Azure AD and On-Behalf-Of Flow. I am trying to exchange a OAuth access token to a SAML Assertion using the On-Behalf-Of flow of Azure AD.
Setup
A Front-End communicating with a Back-End using OAuth access tokens
A datasource which I need to get data from, which is protected with SAML
The request to fetch data from the datasource needs to be performed from the Back-End since there are access restrictions to the datasource in place.
Description
Following the documentation for Azure AD v1 (Github docs), I was able to request a response which initially looks fine. The parameters for the request I used are:
grant_type: urn:ietf:params:oauth:grant-type:jwt-bearer
assertion: <access token containing the correct scopes for the Back-End>
client_id: <client-id-of-back-end>
client_secret: <assigned-secret>
resource: <resource-of-the-datasource>
requested_token_use: on_behalf_of
requested_token_type: urn:ietf:params:oauth:token-type:saml2
The request is sent as POST request, using x-www-form-urlencoded as content-type (endpoint "https://login.microsoftonline.com/tenant-id/oauth2/token").
Issue
I am almost certain, I am encountering a bug, however I did not figure out how to contact Azure without having a Developer Support Plan. The response I receive looks fine at first:
{
"token_type": "Bearer",
"expires_in": "3579",
"ext_expires_in": "3579",
"expires_on": "1613985579",
"resource": "<datasource>",
"access_token": "PEFzc2Vyd...9uPg",
"issued_token_type": "urn:ietf:params:oauth:token-type:saml2",
"refresh_token": "0.ATEAt...hclkg-7g"
}
The assertion from the access_token field is not a valid base64 string. Trying to decode it using C# Base64Convert, results in this exception:
System.FormatException: The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters.
I was however able to partly decode it using bashs base64 -D, which gave me a somehow valid assertion:
$ base64 -D "response.txt"
Invalid character in input stream.
<Assertion ID="_26be6964-2e17-4184-8ac7-d4cdbb9d5700" IssueInstant="2021-02-22T12:35:49.919Z" Version="2.0" xmlns="urn:oasis:names:tc:SAML:2.0:assertion"><Issuer>https://sts.windows.net/[id]/</Issuer><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/><Reference URI="#_26be6964-2e17-4184-8ac7-d4cdbb9d5700"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>...<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"><AttributeValue>test#domain.com</
Question
I am almost sure, that the assertion should be a valid base64 string to decode using anything capable of doing so. Am I missing something? Or is this a known issue with V1 OBO Flow? Is there a known workaround for this?
the assertion is the access-token that you receive in the initial call to AAD as mentioned here.
This is a JWT token which is Based64 URL encoded and can be decoded using tools like https://JWT.io or https://JWT.ms or using any programming language too. The main point is that if the access-token issued is a valid access-token, it should get decoded, and that's the same access-token that gets added in the subsequent call to fetch a SAML token.
You can also check the following article that speaks on OBO flow: https://blogs.aaddevsup.xyz/2019/08/understanding-azure-ads-on-behalf-of-flow-aka-obo-flow/
The main point to note here would be how we are requesting the initial Access-token from AAD. If your Front-end is a SPA and if you are using Implicit Flow there, you might want to take a look at this "As of May 2018, some implicit-flow derived id_token can't be used for OBO flow. Single-page apps (SPAs) should pass an access token to a middle-tier confidential client to perform OBO flows instead."
While decoding a JWT, it first needs to be converted to a Base64 encoded string from a Base64URL encoded string. Once the JWT is base64 encoded, then it needs to be decoded and later on parse that into json.
A Powershell Sample for the same:
$token = "<put the jwt here>"
if (!$token.Contains(".") -or !$token.StartsWith("eyJ")) {
Write-Error "Invalid token" -ErrorAction Stop
}
# Token
foreach ($i in 0..1) {
$data = $token.Split('.')[$i].Replace('-', '+').Replace('_', '/')
switch ($data.Length % 4) {
0 { break }
2 { $data += '==' }
3 { $data += '=' }
}
}
$decodedToken = [System.Text.Encoding]::UTF8.GetString([convert]::FromBase64String($data)) | ConvertFrom-Json
Write-Verbose "JWT Token:"
Write-Verbose $decodedToken
C# sample:
static void jwtDecoder()
{
try
{
Console.WriteLine("JWT to Decode: " + jwtEncodedString + "\n");
var jwtHandler = new JwtSecurityTokenHandler();
var readableToken = jwtHandler.CanReadToken(jwtEncodedString);
if (readableToken != true)
{
Console.WriteLine("\n\nThe token doesn't seem to be in a proper JWT format.\n\n");
}
if (readableToken == true)
{
var token = jwtHandler.ReadJwtToken(jwtEncodedString);
var headers = token.Header;
var jwtHeader = "{";
foreach (var h in headers)
{
jwtHeader += '"' + h.Key + "\":\"" + h.Value + "\",";
}
jwtHeader += "}";
Console.Write("\nHeader :\r\n" + JToken.Parse(jwtHeader).ToString(Formatting.Indented));
var claims = token.Claims;
var jwtPayLoad = "{";
foreach (Claim c in claims)
{
jwtPayLoad += '"' + c.Type + "\":\"" + c.Value + "\",";
}
jwtPayLoad += "}";
Console.Write("\r\nPayload :\r\n" + JToken.Parse(jwtPayLoad).ToString(Formatting.Indented));
var jwtSignature = "[RawSignature: ";
jwtSignature += token.RawSignature;
jwtSignature += " ]";
Console.Write("\r\nSignature :\r\n" + jwtSignature);
//Console.ReadLine();
}
}
finally
{
Console.Write("\n\nPress Enter to close window ...");
Console.Read();
}
}

How do I Get the Token I Need to for my Script to hit my Azure Stored Procedure?

I have an azure stored procedure, and I need to hit it with a python script that I'm going to upload as a webjob to schedule it to run once per day.
I've been reading the docs on executing a stored procedure, the common request headers for Azure Cosmos DB rest calls, and the page on access control, but the access control page mentions that these keys are for read queries only (so I assume not for hitting stored procedures, which have rights to do any sort of query or else that seems like a huge vulnerability hole).
I need to know specifically how do I get a key from Azure in python to hit my stored procedure endpoint?
Update 1
I was able, finally, to construct the Authorization string and send it, along with some other headers, to the server. But I am still getting an unauthorized response.
The response:
{
"code": "Unauthorized",
"message": "The input authorization token can't serve the request. Please check that the expected payload is built as per the protocol, and check the key being used. Server used the following payload to sign: 'post\nsprocs\ndbs/metrics/colls/LoungeVisits/sprocs/calculateAverage\nfri, 05 oct 2018 19:06:17 gmt\n\n'\r\nActivityId: 41cd36af-ad0e-40c3-84c8-761ebd14bf6d, Microsoft.Azure.Documents.Common/2.1.0.0"
}
The request headers:
{
Authorization: [my-auth-string],
x-ms-version: "2017-02-22", //My DB was created after this, the latest version, so I assume it uses this version; can I verify this somehow?
x-ms-date: "Fri, 05 Oct 2018 19:06:17 GMT", // My js for returning the auth string also returns the date, so I copy both in
Content-Type: application/json
}
Code to generate auth string which is then copy/pasted into Postman:
var crypto = require("crypto");
var inputKey = "my-key-from-azure";
var today = new Date().toUTCString();
console.log(today);
console.log(getAuthorizationTokenUsingMasterKey("POST", "dbs", "dbs/ToDoList", today, inputKey))
function getAuthorizationTokenUsingMasterKey(verb, resourceType, resourceId, date, masterKey)
{
var key = new Buffer(masterKey, "base64");
var text = (verb || "").toLowerCase() + "\n" +
(resourceType || "").toLowerCase() + "\n" +
(resourceId || "") + "\n" +
date.toLowerCase() + "\n" +
"" + "\n";
var body = new Buffer(text, "utf8");
var signature = crypto.createHmac("sha256", key).update(body).digest("base64");
var MasterToken = "master";
var TokenVersion = "1.0";
return encodeURIComponent("type=" + MasterToken + "&ver=" + TokenVersion + "&sig=" + signature);
}
The page about authorization headers is for any Cosmos DB REST request: query, stored procedures, etc.
Azure cosmos DB has python SDK which is the recommended and supported way for such scenarios.
Also python SDK code is open-sourced. Here is the reference to auth header creation code enter link description here

Add variables to reply URLs in Azure B2C

I am trying to set the redirect_uri in Azure B2C. I have a language field in the Url like this:
https://mydomain/de-de/projects
https://mydomain/en-us/projects
https://mydomain/sv-se/projects
https://mydomain/ar-sa/projects
...
and to be correctly redirected, I have to add all the possibilities to the B2C Reply URLs and I am only limited to 20 max.
Is there a way to add variables to the redirect_uri?
Something like:
https://mydomain/:lang/projects
where ":lang" is a variable the could take any value.
////////////////////////////////////
Solution
The tricky solution was to manipulate the state and inject it with the returned URL due to the fact that it will be sent back after the login/signup response. createLoginUrl() method:
let url = that.loginUrl
+ '?response_type='
+ response_type
+ '&client_id='
+ encodeURIComponent(that.clientId)
+ '&state='
+ encodeURIComponent((state) + 'url' + returnedUrl)
+ '&redirect_uri='
+ encodeURIComponent(window.location.origin)
+ '&scope='
+ encodeURIComponent(that.scope);
so here I split the state with 'url' word so I can read it again after the response came.
encodeURIComponent((state) + 'url' + returnedUrl)
An important details redirect_uri, it should be the same origin:
'&redirect_uri=' + encodeURIComponent(window.location.origin)
and this URL should be added to the returned URL in Azure B2C application.
Now I can split it again in tryLogin() method:
const statePartsWithUrl = (parts['state'] + '').split('url');
window.location.href = statePartsWithUrl[1];
and it works perfectly.
////-------------------------------------
Edit : 1.2.2019
const statePartsWithUrl = (parts['state'] + '').split('url');
let state = '';
let returnedUrl = '';
if (statePartsWithUrl != null) {
state = statePartsWithUrl[0];
returnedUrl = statePartsWithUrl[1];
}
Here is the splitting of the state to read the information from it in method tryLogin(options)
Yeah so as you found out, you can't currently add wildcards to reply URLs in B2C.
This may be due to security concerns defined in the OAuth 2.0 Threat Model and Security Considerations RFC.
In it, the suggested counter-measure against Open Redirect Attacks is to have the client register the full redirect URI.
There is also no way to create apps programmatically: https://feedback.azure.com/forums/169401-azure-active-directory/suggestions/19975480-programmatically-register-b2c-applications.
So sadly the manual way is the only way at the moment. But be sure to go upvote the feature request on User Voice.
I actually even tried to manually edit an app via Graph Explorer:
{
"odata.error": {
"code": "Request_BadRequest",
"message": {
"lang": "en",
"value": "Updates to converged applications are not allowed in this version."
},
"date": "2018-01-08T12:00:00",
"requestId": "208e7159-d459-42ec-8bb7-000000000000",
"values": null
}
}
As you suggested in the comments, one way to work around this problem would be to use a single static redirect URI and keep the language/culture in the state/a cookie, and then do the redirect to the language-specific version after the user is returned to the app.

Unable to test docusign in SOAPUI

I ma trying to test docusign REST API using soapui. But it throwing an error
{
"errorCode": "PARTNER_AUTHENTICATION_FAILED",
"message": "The specified Integrator Key was not found or is disabled. An Integrator key was not specified."
}
I have an demo account and integration key setup. Please help.
Thanks
Bharat
Looks like you are specifying the wrong integrator Key.
If you are using the legacy authentication Header, make sure you are passing it as follows.
<DocuSignCredentials>
<Username>developer#example.com</Username>
<Password>S3cre+p455w0Rd</Password>
<IntegratorKey>your integrator key</IntegratorKey>
</DocuSignCredentials>'
If you are using oAuth. Look at this documentation.
Using Json via Rest API at https://demo.docusign.net/restapi/v2 , always remember to include below code for all your requests to DocuSign.
string authHeader = "{\"Username\":\"" + _username + "\", \"Password\":\"" + _password + "\", \"IntegratorKey\":\"" + _integratorKey + "\"}";
WebRequest req = WebRequest.Create(url);
req.Headers.Add("X-DocuSign-Authentication", authHeader);

Resources