Generating RSA JWT in Postman Pre-request script - google-api

I have the following pre-request script that i am using to attempt to generate a JWT for Google Api - Google uses the RS256 encryption which is where I think I am getting stuck - the CryptoJS seems to support HmacSHA256 only - Any advise would be helpful:
Here's my pre-request script from Postman:
function base64url(source) {
// Encode in classical base64
encodedSource = CryptoJS.enc.Base64.stringify(source);
// Remove padding equal characters
encodedSource = encodedSource.replace(/=+$/, '');
// Replace characters according to base64url specifications
encodedSource = encodedSource.replace(/\+/g, '-');
encodedSource = encodedSource.replace(/\//g, '_');
return encodedSource;
}
function addIAT(request) {
var iat = Math.floor(Date.now() / 1000) - 100;
data.iat = iat;
return data;
}
function addEXP(request) {
var exp = Math.floor(Date.now() / 1000) + 3300;
data.exp = exp;
return data;
}
var header = {
"alg": "RS256",
"typ": "JWT",
"kid": "xxx"
};
var data = {
"iss": "xxx#iam.gserviceaccount.com",
"aud": "https://oauth2.googleapis.com/token",
"scope": "https://www.googleapis.com/auth/cloud-platform"
};
data = addIAT(data);
data = addEXP(data);
var privateKEY = "-----BEGIN PRIVATE KEY-----xxxxxxxxxxxxxxxLcGGNkna2Y3URoT0vDNneqzaasmJk4JZ97BcFLOulTihA49z8zmQKBgQDKX9AWS88cnfyiXSxtRNUFYvN4SzMDTJ1o59Gm6Sk77t7Ylfm+8PKA00SQeN7FuU/cbU4PkbAyzcp7eAGE3KXoLC/pWQ14srWGAsQkti1PmBo400ajRQReJPs3XxIl3yl4swlRgn+w9x6xy3CRnWrZRQSxRrtdDkBJcp7Lml+4mwKBgQCCeiTsktlMTOy9LqxOUMh6Lt7Z5jceNSwusW8Z4YVsewiSsRezufLBRcTywifgPOyUTP3S7etEfW2CKF0smpM0drfxd/3Ic7oKr7ESY5zwNcV7Q3NUGxaqGy8yoxEhKkLsYkOzYUdyNyfJd5Sh8yq7ICrX7/UGkVLOi44VrdaluQKBgC3kmH3V5zvoH/h6BK8q4tv72pa3BvSClVfK6mJdkbpDq0mWiTJh1bydLHlOz8YrBg9IwmEJetmqjXZ+emm01/LUwnC6fzGV5VBkpDJnFdNs/NVSJDy2VA09ebLO3oC0IOV8RGq1m1t4Tv+m0PpUpnxrCGtjTO4HY1DEq3okofxtAoGABjq4QegVIlImU5LSAEKgnUiwA1CHGW3+ZzfCczAv2VRfk/DSlYLmsxLRIfjsCVEo79NiVGyIsKmt5TJRxVLXp++ydKCEN/YRrjqEFgHNoH0rDCuV/IKAeN17/TYKphuebSX6mVsfo7GXI1kSoGJkDDnPKR4peiIF/YC9BTqQgIs=-----END PRIVATE KEY-----"
var secret = 'myjwtsecret';
// encode header
var stringifiedHeader = CryptoJS.enc.Utf8.parse(JSON.stringify(header));
var encodedHeader = base64url(stringifiedHeader);
// encode data
var stringifiedData = CryptoJS.enc.Utf8.parse(JSON.stringify(data));
var encodedData = base64url(stringifiedData);
//encode privatekey
//var stringifiedPrivatekey = CryptoJS.enc.Utf8.parse(JSON.stringify(privateKEY));
//var encodedPrivatekey = base64url(stringifiedPrivatekey);
// build token
var token = encodedHeader + "." + encodedData
// sign token
//var signature = CryptoJS.HmacSHA256(token, secret);
//signature = base64url(signature);
var signature = CryptoJS.RS256(token , privateKEY);
signedToken = base64url(signature);
var jwt = token + "." + signedToken
postman.setEnvironmentVariable("payload", jwt);

I have found this problem a couple of time in my projects so I decide to create an easy way to do this, here https://joolfe.github.io/postman-util-lib/ i have publish a ¨library¨ to easy do cryptographic operations like generate jwt, PKCE challenges... in ¨Pre-request¨ and ¨Tests¨ scripts in postman, have a look and contact me if you have any doubts.
Best Regards.

Related

Google Users: List users data of a specific group

I am in the need of listing the users data belonging to a specific group within the organization. The documentation does not specify if this is possible. I was really hoping there could be some kind of query that would allow this. For example email in (1#domain.com,2#domain.com). However, I don't see that being possible. The only way I could think to accomplish this would be:
Get a list of all the members in the group (https://developers.google.com/admin-sdk/directory/reference/rest/v1/members/list)
Get each user data by email (https://developers.google.com/admin-sdk/directory/reference/rest/v1/users/get)
The problem with the above approach is that if a group contains 50+ members, this means that I have to make all that amount of requests, which is counter productive. Imagine how long that would take.
Any ideas? Greatly appreciate it.
Unfortunately I don’t think you can skip this two step process, but you can speed it up using batch requests. This
allows you to request up to 1000 calls in a single request. The steps would be:
Make a batch request to get all the members of all the groups you want (using members.list).
Make a batch request to get all the user info that you need using their id (using user.get).
Notice that the data in the result won’t be sorted, but they will be tagged by Content-ID.
References
Sending Batch Requests (Directory API)
Method: members.list (Directory API)
Method: users.get (Directory API)
I thought about the batching request a couple of hours after I posted the question. The problem with Node JS is that it does not has built in support for batch requests, unlike the php client library for example; Therefore, I had to spent some time implementing support for it on my own since I was not able to find any example. I'll share the solution in case it helps someone else or for my future reference.
async function getGroupMembersData(){
const groupEmail = "group#domain.com"; //google group email
const groupMembers = await getGroupMembers(groupEmail).catch(error=>{
console.error(`Error querying group members: ${error.toString()}`);
});
if(!groupMembers){ return; }
const url = "https://www.googleapis.com/batch/admin/directory_v1";
const scopes = ["https://www.googleapis.com/auth/admin.directory.user.readonly"];
const requests = [];
for(let i=0; i<groupMembers.length; ++i){
const user = groupMembers[i];
const request = {
email: user,
endpoint: `GET directory_v1/admin/directory/v1/users/${user}?fields=*`
};
requests.push(request);
}
const batchRequestData = await batchProcess(url, scopes, requests).catch(error=>{
console.error(`Error processing batch request: ${error.toString()}`);
});
if(!batchRequestData){ return; }
const usersList = batchRequestData.map(i=>{
return i.responseBody;
});
console.log(usersList);
}
//get group members using group email address
async function getGroupMembers(groupKey){
const client = await getClient(scopes); //function to get an authorized client, you have to implement on your own
const service = google.admin({version: "directory_v1", auth: client});
const request = await service.members.list({
groupKey,
fields: "members(email)",
maxResults: 200
});
const members = !!request.data.members ? request.data.members.map(i=>i.email) : [];
return members;
}
//batch request processing in groups of 100
async function batchProcess(batchUrl, scopes, requests){
const client = await getClient(scopes); //function to get an authorized client, you have to implement on your own
let results = [];
const boundary = "foobar99998888"; //boundary line definition
let batchBody = ""; const nl = "\n";
const batchLimit = 100; //define batch limit (max supported = 100)
const totalRounds = Math.ceil(requests.length / batchLimit);
let batchRound = 1;
let batchItem = 0;
let roundLimit = batchLimit;
do{
roundLimit = roundLimit < requests.length ? roundLimit : requests.length;
//build the batch request body
for(batchItem; batchItem<roundLimit; batchItem++){
const requestData = requests[batchItem];
batchBody += `--${boundary}${nl}`;
batchBody += `Content-Type: application/http${nl}`;
batchBody += `Content-Id: <myapprequest-${requestData.email}>${nl}${nl}`;
batchBody += `${requestData.endpoint}${nl}`;
}
batchBody += `--${boundary}--`;
//send the batch request
const batchRequest = await client.request({
url: batchUrl,
method: "POST",
headers: {
"Content-Type": `multipart/mixed; boundary=${boundary}`
},
body: batchBody
}).catch(error=>{
console.log("Error processing batch request: " + error);
});
//parse the batch request response
if(!!batchRequest){
const batchResponseData = batchRequest.data;
const responseBoundary = batchRequest.headers["content-type"].split("; ")[1].replace("boundary=", "");
const httpResponses = batchResponseParser(batchResponseData, responseBoundary);
results.push(...httpResponses);
}
batchRound++;
roundLimit += batchLimit;
} while(batchRound <= totalRounds);
return results;
};
//batch response parser
function batchResponseParser(data, boundary){
const nl = "\r\n";
data = data.replace(`--${boundary}--`,"");
const responses = data.split(`--${boundary}`);
responses.shift();
const formattedResponses = responses.map(i=>{
const parts = i.split(`${nl}${nl}`);
const responseMetaParts = (parts[0].replace(nl, "")).split(nl);
let responseMeta = {};
responseMetaParts.forEach(part=>{
const objectParts = part.split(":");
responseMeta[objectParts[0].trim()] = objectParts[1].trim();
});
const responseHeadersParts = parts[1].split(nl);
let responseHeaders = {};
responseHeadersParts.forEach(part=>{
if(part.indexOf("HTTP/1.1") > -1){
responseHeaders.status = part;
} else {
const objectParts = part.split(":");
responseHeaders[objectParts[0].trim()] = objectParts[1].trim();
}
});
const reg = new RegExp(`${nl}`, "g");
const responseBody = JSON.parse(parts[2].replace(reg, ""));
const formatted = {
responseMeta: responseMeta,
responseHeaders: responseHeaders,
responseBody: responseBody
};
return formatted;
});
return formattedResponses;
}

502 on AWS Cognito ListUsers with PaginationToken

Using AWSMibileHub to set up my backend. Working on an admin page that shows all the users from AWS Cognito.
I’m using ListUsers to get user list and noticed 502 error on the request with a PagenationToken and it seems to be happening randomly.
In CloudWatch shows this error below.
InvalidParameterException: 1 validation error detected: Value 'CAISlAIIARLtAQgDEugBADSdLB5dZXQEaQjoL8y8CE1RGGT3PZ4FpCqxFwJkNuhIeyJAbiI6IlBhZ2luYXRpb25Db250aW51YXRpb25EVE8iLCJuZXh0S2V5IjoiQUFBQUFBQUFCZHM4QVFFQmJBZmU5OFgzUnJTM1BHcnYzVmRiVWNScVdIck82VXFZaTdlZklleVRCSEZsYm1ZN01UVTRPV1k0TVRNdE9UYzVZUzAwWTJKakxUazROekl0TkdRek9UYzROMlpoWmpVM093PT0iLCJwcmV2aW91c1JlcXVlc3RUaW1lIjoxNTQzMDkzODIyNDk5fRogNk7FThSKBOuwQGi DoZBnmNN85UY5oFiSAbHWfOzreY=' at 'paginationToken' failed to satisfy constraint: Member must satisfy regular expression pattern: [\S]+
Does anybody have the same issue or any idea how to fix this issue?
Store the pagination Token in a variable and then add this .replace(/\ /g,'+') to the variable to change the space back to +.
e.g:
const pagination = 'TOKEN FROM COGNITO'.replace(/\ /g,'+')
The pagination_token consists of non alphanumeric characters, so its better to encrypt and decrypt when required.
Encrypt?decrypt utility file
const crypto = require("crypto");
const algorithm = "aes-256-ctr";
const password = "sassed";
class Util {
static encrypt_aes(text) {
let cipher = crypto.createCipher(algorithm, password);
let crypted = cipher.update(text, "utf8", "hex");
crypted += cipher.final("hex");
return crypted;
}
static decrypt_aes(text) {
let decipher = crypto.createDecipher(algorithm, password);
let dec = decipher.update(text, "hex", "utf8");
dec += decipher.final("utf8");
return dec;
}
}
module.exports = Util;
PaginationToken encryption/decription
const Util = require("./utils");
class Users {
static async getUsersAttributes(params) {
let listparams = {
UserPoolId: userPoolID /* required */,
Limit: params.limit || 10,
};
if (params.paginationToken) {
listparams.PaginationToken = Util.decrypt_aes(params.paginationToken);
}
let response = await cognitoISPClient.listUsers(listparams).promise();
response.PaginationToken = Util.encrypt_aes(response.PaginationToken);
return response;
}
}

Connecting xamarin to woocommerce api

I'm trying to create my first app that will connect to a woocommerce api.
Has anyone any experience in this or can point me in the direction as to how to create a connection to pull in the product list?
Thanks
Since WooCommerce has a REST API, it should be fairly simple to connect using a plain HTTP request, or a library like RestSharp.
There is also a C# client for WooCommerce - I don't know if it plays well with Xamarin, you might need to modify it a bit to get it to build.
var api = new WoocommerceApiClient(StoreUrl, ConsumerKey, ConsumerSecret);
var result = await api.Products.Get();
It's an old post but I had faced a similar issue. I had tries WoocommerceSharp with Xamarin Studio 6.1.1 (mac version); I opened the .sln file, added the missing reference to system.net.http and it worked perfectly.
If you want make it work in PCL you have to use PCLCrypto in WoocommerceApiUrlGenerator.cs , here the updated version:
namespace SharpCommerce.Web
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using PCLCrypto;
internal class WoocommerceApiUrlGenerator
{
private const string SignatureMethod = "HMAC-SHA1";
private const string ApiV3RootEndpoint = "wc-api/v3/";
private readonly string baseURI;
private readonly string consumerKey;
private readonly string consumerSecret;
internal WoocommerceApiUrlGenerator(string storeUrl, string consumerKey, string consumerSecret)
{
if (
string.IsNullOrEmpty(consumerKey) ||
string.IsNullOrEmpty(consumerSecret) ||
string.IsNullOrEmpty(storeUrl))
{
throw new ArgumentException("ConsumerKey, consumerSecret and storeUrl are required");
}
this.consumerKey = consumerKey;
this.consumerSecret = consumerSecret;
// Need 'http://www.example.com' to be 'http://www.example.com/wc-api/v3/'
this.baseURI = String.Format("{0}/{1}", storeUrl.TrimEnd('/'), ApiV3RootEndpoint);
}
internal string GenerateRequestUrl(HttpMethod httpMethod, string apiEndpoint, Dictionary<string, string> parameters = null)
{
parameters = parameters ?? new Dictionary<string, string>();
parameters["oauth_consumer_key"] = this.consumerKey;
// oauth_timestamp = number of seconds since 1/1/1970 00:00:00 GMT
// must be a positive integer
// must be greater than timestamp of previous requests
parameters["oauth_timestamp"] =
Math.Round(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds).ToString(CultureInfo.InvariantCulture);
// oauth_nonce = a unique random string for the timestamp.
// defends against replay attacks
// service provide will know that this request has never been made before.
// Just going to hash the time stamp.
//parameters["oauth_nonce"] = GenerateNonce(parameters["oauth_timestamp"]);
// Create random 32 char alphnumeric to avoid reused nonces
parameters["oauth_nonce"] = GenerateNonce();
// Declare the hashing method your using
parameters["oauth_signature_method"] = SignatureMethod;
//parameters["oauth_version"] = "1.0";
parameters["oauth_signature"] = UpperCaseUrlEncode(this.GenerateSignature(httpMethod, apiEndpoint, parameters));
var sb = new StringBuilder();
foreach (var pair in parameters)
{
sb.AppendFormat("&{0}={1}", SafeUpperCaseUrlEncode(pair.Key), SafeUpperCaseUrlEncode(pair.Value));
}
// Substring removes first '&'
var queryString = sb.ToString().Substring(1);
var url = this.baseURI + apiEndpoint + "?" + queryString;
return url;
}
private string GenerateSignature(HttpMethod httpMethod, string apiEndpoint, Dictionary<string, string> parameters)
{
// 1) Set the HTTP method for the request.
// set through 'method'
//2) Set your base request URI – this is the full request URI without query string parameters – and URL encode according to RFC 3986:
// need 'http://www.example.com/wc-api/v3/orders'
// to become: 'http%3A%2F%2Fwww.example.com%2Fwc-api%2Fv1%2Forders'
var encodedBaseRequestURI = SafeUpperCaseUrlEncode(this.baseURI + apiEndpoint);
// 3) Collect and normalize your query string parameters
// percent(%) characters should be double-encoded (e.g. % becomes %25.
var normalizedParameters = NormalizeParameters(parameters);
// 4) Sort the parameters in byte-order
var orderedNormalizedParameters = normalizedParameters.OrderBy(x => x.Key).ToList();
// 5) Join each parameter with an encoded equals sign (%3D):
//var joinedOrderedNormalizedParameters = orderedNormalizedParameters.ConvertAll(x => x.Key + "%3D" + x.Value);
var joinedOrderedNormalizedParameters = new List<string>();
foreach (var x in orderedNormalizedParameters)
{
joinedOrderedNormalizedParameters.Add(x.Key + "%3D" + x.Value);
}
// 6) Join each parameter key/value pair with an encoded ampersand (%26):
var joinedParameterPairs = String.Join("%26", joinedOrderedNormalizedParameters);
// 7) Form the string to sign by joining the HTTP method, encoded base request URI, and encoded parameter string with an unencoded ampersand symbol (&):
var stringToSign = string.Format("{0}&{1}&{2}", httpMethod.ToString().ToUpper(), encodedBaseRequestURI, joinedParameterPairs);
// 8) Generate the signature using the string to key and your consumer secret key
var preparedStringToSign = Encoding.UTF8.GetBytes(stringToSign);
var secret = this.consumerSecret + "&";
var preparedConsumerKey = Encoding.UTF8.GetBytes(secret);
var signatureHash = Sha1(preparedConsumerKey, preparedStringToSign);
var signatureString = Convert.ToBase64String(signatureHash);
return signatureString;
}
private static byte[] Sha1(byte[] key, byte[] message)
{
var mac = WinRTCrypto.MacAlgorithmProvider.OpenAlgorithm(MacAlgorithm.HmacSha1);
//var keyMaterial = WinRTCrypto.CryptographicBuffer.ConvertStringToBinary(key, Encoding.UTF8);
var cryptoKey = mac.CreateKey(key);
var hash = WinRTCrypto.CryptographicEngine.Sign(cryptoKey, message);
return hash;
//return WinRTCrypto.CryptographicBuffer.CreateFromByteArraymessage);
}
private static Dictionary<string, string> NormalizeParameters(Dictionary<string, string> parameters)
{
var result = new Dictionary<string, string>();
foreach (var pair in parameters)
{
var upperCaseUrlEncodedKey = SafeUpperCaseUrlEncode(pair.Key);
var normalizedKey = upperCaseUrlEncodedKey.Replace("%", "%25");
var upperCaseUrlEncodedValue = SafeUpperCaseUrlEncode(pair.Value);
var normalizedValue = upperCaseUrlEncodedValue.Replace("%", "%25");
result.Add(normalizedKey, normalizedValue);
}
return result;
}
private static string SafeUpperCaseUrlEncode(string stringToEncode)
{
return UpperCaseUrlEncode(System.Net.WebUtility.UrlDecode(stringToEncode));
}
private static string UpperCaseUrlEncode(string stringToEncode)
{
var basicUrlEncodedString = System.Net.WebUtility.UrlEncode(stringToEncode);
if (String.IsNullOrEmpty(basicUrlEncodedString)) return String.Empty;
var upperCaseUrlEncodedString = Regex.Replace(
basicUrlEncodedString,
"(%[0-9a-f][0-9a-f])",
c => c.Value.ToUpper());
return upperCaseUrlEncodedString;
}
private static string GenerateNonce()
{
const string ValidChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var random = new Random();
var nonceString = new StringBuilder();
for (var i = 0; i < 32; i++)
{
nonceString.Append(ValidChars[random.Next(0, ValidChars.Length - 1)]);
}
return nonceString.ToString();
}
}
}
and in WoocommerceApiDriver.cs you will have to replace
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return await client.GetStringAsync(url);
}
by
using (var client = new HttpClient()) // must use to avoid Android freezes after repeated calls
{
Task<HttpResponseMessage> r = client.GetAsync(url);
HttpResponseMessage m = r.Result;
return await m.Content.ReadAsStringAsync();
}
Et voila ! ca marche ;)

SignatureVerificationFailedException in JwtAuthForWebAPI

I have wired up the JwtAuthForWebAPI nuget project but I am not able to validate the generated tokens. I end up getting a 500 error. I am using the exact same key value for both token generation and also when configuring JwtAuthenticationMessageHandler.
This is the code to generate a token:
var tokenHandler = new JwtSecurityTokenHandler();
var symmetricKey = JsonWebTokenSecretKey.GetBytes();
var now = DateTime.UtcNow;
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(
new[]{
new Claim(JwtClaimKeys.Audience, SessionManager.Current.ApplicationId.ToString()),
new Claim(JwtClaimKeys.Subject, userLoginRequest.ApplicationInstanceId.ToString())
}),
TokenIssuerName = "My Company",
Lifetime = new Lifetime(now, now.AddMinutes(tokenLifetimeInMinutes)),
SigningCredentials = new SigningCredentials(
new InMemorySymmetricSecurityKey(symmetricKey),
"http://www.w3.org/2001/04/xmldsig-more#hmac-sha256",
"http://www.w3.org/2001/04/xmlenc#sha256")
};
tokenDescriptor.Subject.AddClaims(GetRoles(userLoginRequest));
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
This is the code to register the authentication handler:
var keyBuilder = new SecurityTokenBuilder();
var jwtHandler = new JwtAuthenticationMessageHandler
{
Issuer = "My Company",
AllowedAudience = ApplicationId.ToString(),
SigningToken = keyBuilder.CreateFromKey(JsonWebTokenSecretKey),
PrincipalTransformer = new MyUserPrincipleTransformer()
};
config.MessageHandlers.Add(jwtHandler);
This is the error I get:
{"Message":"An error has occurred.","ExceptionMessage":"IDX10503: Signature validation failed. Keys tried: 'System.IdentityModel.Tokens.InMemorySymmetricSecurityKey\r\n'.\nExceptions caught:\n ''.\ntoken: '{\"typ\":\"JWT\",\"alg\":\"HS256\"}.{\"aud\":\"1\",\"sub\":\"3\",\"role\":[\"User\",\"Admin\"],\"iss\":\"My Company\",\"exp\":1429547369,\"nbf\":1429543769}'","ExceptionType":"System.IdentityModel.SignatureVerificationFailedException",
"StackTrace":"
at System.IdentityModel.Tokens.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)\r\n
at System.IdentityModel.Tokens.JwtSecurityTokenHandler.ValidateToken(String securityToken, TokenValidationParameters validationParameters, SecurityToken& validatedToken)\r\n
at JwtAuthForWebAPI.JwtSecurityTokenHandlerAdapter.ValidateToken(IJwtSecurityToken securityToken, TokenValidationParameters validationParameters)\r\n
at JwtAuthForWebAPI.JwtAuthenticationMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n
at System.Web.Http.HttpServer.<SendAsync>d__0.MoveNext()"}
This is an example JSON token:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxIiwic3ViIjoiMyIsInJvbGUiOlsiVXNlciIsIkFkbWluIl0sImlzcyI6Ik15IENvbXBhbnkiLCJleHAiOjE0Mjk1NTE4MjgsIm5iZiI6MTQyOTU0ODIyOH0.9wA_RBir9u7Cn_-Fy2T-Q_IDUfz6B928IEbIgXD9Bug
Interestingly, I am able to validate the token with my key using http://jwt.io. I suspect it may have something to do with the JwtAuthForWebAPI library looking at something different than what the System.Identity JWT library is generating?
this is Jamie (author of the JwtAuthForWebAPI package). The server config code - specifically, SecurityTokenBuilder.CreateFromKey(string) - assumes the given string is base64 encoded. It was either that, or assumptions or parameters are needed that would indicate which encoding to use for converting to a byte array. I chose to assume the string was base64 encoded. I'm sure there's a clearer way to go about converting the string key into a SecurityToken, but that's the way the code is today.
In SmokeTests.cs within the JwtAuthForWebAPI.SampleClient project, you can see that I used the Convert.FromBase64String() method, as opposed to using the GetBytes() method from an Encoding class:
public const string SymmetricKey = "YQBiAGMAZABlAGYAZwBoAGkAagBrAGwAbQBuAG8AcABxAHIAcwB0AHUAdgB3AHgAeQB6ADAAMQAyADMANAA1AA==";
// ...
var key = Convert.FromBase64String(SymmetricKey);
var credentials = new SigningCredentials(
new InMemorySymmetricSecurityKey(key),
"http://www.w3.org/2001/04/xmldsig-more#hmac-sha256",
"http://www.w3.org/2001/04/xmlenc#sha256");
Feel free to keep using your current token generation code, but on the server...
Please try specifying a base64 encoded version of JsonWebTokenSecretKey in the server configuration code. You can use a site like https://www.base64encode.org/ to encode it, or try code like this:
var base64key = Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonWebTokenSecretKey));
var keyBuilder = new SecurityTokenBuilder();
var jwtHandler = new JwtAuthenticationMessageHandler
{
Issuer = "My Company",
AllowedAudience = ApplicationId.ToString(),
SigningToken = keyBuilder.CreateFromKey(base64key),
PrincipalTransformer = new MyUserPrincipleTransformer()
};
Let me know whether or not that works.
Also, I'm going to update the library to catch the SignatureVerificationFailedException exception and return a 401, as opposed to letting an internal server error happen. You'll still need to specify your key as a base64 string, but at least such configuration issues won't cause a 500 error.
Again, please let me know if that does the trick.
it's just my code sample base on #Jamie answer
protected string GetUsername(string token)
{
string secret = "keyyyyy!#3";
var key = Convert.FromBase64String(secret);
var IssuerSigningKey = new SymmetricSecurityKey(key);
IdentityModelEventSource.ShowPII = true;
var SigningCredentials = new SigningCredentials(
IssuerSigningKey,
SecurityAlgorithms.HmacSha256Signature);
var handler = new JwtSecurityTokenHandler();
var tokenSecure = handler.ReadToken(token) as SecurityToken;
var validations = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = IssuerSigningKey,
ValidateIssuer = false,
ValidateAudience = false
};
var claims = handler.ValidateToken(token, validations, out tokenSecure);
return claims.Identity.Name;
}

here is the code to fetch username and password from the xml file but it does't fetch the the data?

Here is the code to fetch username and password from the xml file but it does't fetch the the data?
private var myXML: XML = new XML();
private function connect(event: Event): void {
var str1: String = username.text.toString();
trace(str1);
var str2: String = password.text.toString();
trace(str2);
var str3: String = myXML.authentication.username;
Alert.show(str3);
var str4: String = myXML.authentication.password;
if (str1 == str3 && str2 == str4) {
Alert.show("sucessfully Connected")
} else {
Alert.show("invalid username password");
}
}
Where you are assigning data for myXML and what is your xml?
var settingFile:File;
var stream:FileStream;
var resultXML:XML;
settingFile = settingFile.resolvePath("setting.xml");
stream = new FileStream;
if(settingFile.exists)
{
stream.open(settingFile,FileMode.READ);
resultXML = XML(stream.readUTFBytes(stream.bytesAvailable));
stream.close();
var xmlDoc:XMLDocument = new XMLDocument(resultXML.toString());
var decoder:SimpleXMLDecoder = new SimpleXMLDecoder(true);
var resultObj:Object = decoder.decodeXML(xmlDoc);
}
from that resultObj u can access the username and password
if you are using FlexApplication then convert the xml file to xmlDocument and decode it. then from the decoded object you can get the username and password.
var xmlDoc:XMLDocument = new XMLDocument(myXML.toString());
var decoder:SimpleXMLDecoder = new SimpleXMLDecoder(true);
var resultObj:Object = decoder.decodeXML(xmlDoc);
you can try like this.
private var myXML: XML = new XML();
private function connect(event: Event): void {
var xmlDoc:XMLDocument = new XMLDocument(myXML.toString());
var decoder:SimpleXMLDecoder = new SimpleXMLDecoder(true);
var resultObj:Object = decoder.decodeXML(xmlDoc);
var str1: String = username.text.toString();
trace(str1);
var str2: String = password.text.toString();
trace(str2);
var str3: String = resultObj.authentication.username;
Alert.show(str3);
var str4: String = resultObj.authentication.password;
if (str1 == str3 && str2 == str4) {
Alert.show("sucessfully Connected")
} else {
Alert.show("invalid username password");
}
}
Why don't you try to load the XML file suing the URL loader and capture the COMPLETE event to fetch the data?

Resources