/*
* Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
using System.Text;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Reflection;
using Amazon.Runtime;
using Amazon.CognitoIdentityProvider.Model;
namespace Amazon.Extensions.CognitoAuthentication.Util
{
internal static class CognitoAuthHelper
{
[ThreadStatic] private static SHA256 sha256 = null;
private static string assemblyFileVersion = null;
///
/// Property to access the thread-safe SHA256 member variable.
/// Creates a SHA256 instance if one does not exist.
///
internal static SHA256 Sha256
{
get
{
if (sha256 == null)
{
sha256 = SHA256.Create();
}
return sha256;
}
}
internal static string AssemblyFileVersion
{
get
{
if (assemblyFileVersion == null)
{
var assembly = typeof(CognitoAuthHelper).GetTypeInfo().Assembly;
AssemblyFileVersionAttribute attribute = assembly.GetCustomAttribute(typeof(AssemblyFileVersionAttribute)) as AssemblyFileVersionAttribute;
assemblyFileVersion = attribute == null ? "Unknown" : attribute.Version;
}
return assemblyFileVersion;
}
}
///
/// Computes the secret hash for the user pool using the corresponding userID, clientID,
/// and client secret
///
/// The current userID
/// The clientID for the client being used
/// The client secret of the corresponding clientID
/// Returns the secret hash for the user pool using the corresponding
/// userID, clientID, and client secret
public static string GetUserPoolSecretHash(string userID, string clientID, string clientSecret)
{
string message = userID + clientID;
byte[] keyBytes = Encoding.UTF8.GetBytes(clientSecret);
byte[] messageBytes = Encoding.UTF8.GetBytes(message);
HMACSHA256 hmacSha256 = new HMACSHA256(keyBytes);
byte[] hashMessage = hmacSha256.ComputeHash(messageBytes);
return Convert.ToBase64String(hashMessage);
}
///
/// Creates a byte array which combines all of the byte[] in values in the order of the array
///
/// An array of byte[] to be combined
/// Returns a byte array which combines all of the byte[] in values
internal static byte[] CombineBytes(params byte[][] values)
{
int combinedLength = 0;
byte[] returnBytes;
int copyIndex = 0;
for (int i = 0; i < values.Length; i++)
{
combinedLength += values[i].Length;
}
returnBytes = new byte[combinedLength];
for (int i = 0; i < values.Length; i++)
{
Buffer.BlockCopy(values[i], 0, returnBytes, copyIndex, values[i].Length);
copyIndex += values[i].Length;
}
return returnBytes;
}
///
/// Converts a hexadecimal string to a byte array
///
/// The hexadecimal string to be converted to a byte array
/// Returns the byte array for the corresponding string
internal static byte[] StringToByteArray(string hexString)
{
if (hexString.Length % 2 != 0)
{
throw new ArgumentException("Malformed hexString.", "hexString");
}
int stringLen = hexString.Length;
byte[] bytes = new byte[stringLen / 2];
for (int i = 0; i < stringLen; i += 2)
{
bytes[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16);
}
return bytes;
}
///
/// Internal method to convert a dictionary of user attributes to a list of AttributeType
///
/// Dictionary containing attributes of type string
/// Returns a List of AttributeType objects
internal static List CreateAttributeList(IDictionary attributeDict)
{
List attributeList = new List();
foreach (KeyValuePair data in attributeDict)
{
AttributeType attribute = new AttributeType()
{
Name = data.Key,
Value = data.Value
};
attributeList.Add(attribute);
}
return attributeList;
}
///
/// Internal method for handling metrics
///
private const string UserAgentHeader = "User-Agent";
internal static void ServiceClientBeforeRequestEvent(object sender, RequestEventArgs e)
{
Amazon.Runtime.WebServiceRequestEventArgs args = e as Amazon.Runtime.WebServiceRequestEventArgs;
if (args == null || !args.Headers.ContainsKey(UserAgentHeader))
return;
var metric = " AWSDotNetCognito/" + AssemblyFileVersion;
if (!args.Headers[UserAgentHeader].Contains(metric))
{
args.Headers[UserAgentHeader] = args.Headers[UserAgentHeader] + metric;
}
}
}
}