Skip to content

feat(icp4d): refactor iam token manager and add icp4d support #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 182 additions & 0 deletions Authentication/IamTokenManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
/**
* Copyright 2019 IBM Corp. 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 IBM.Cloud.SDK.Connection;
using IBM.Cloud.SDK.Utilities;
using System;
using System.Collections.Generic;
using UnityEngine.Networking;
using Newtonsoft.Json;
using System.Text;
using Utility = IBM.Cloud.SDK.Utilities.Utility;


namespace IBM.Cloud.SDK.Authentication
{
public class IamTokenManager : JwtTokenManager
{
private string iamApikey;
private string iamClientId;
private string iamClientSecret;
private string iamDefaultUrl = "https://iam.cloud.ibm.com/identity/token";

private const string CLIENT_ID_SECRET_WARNING = "Warning: Client ID and Secret must BOTH be given, or the defaults will be used.";

public IamTokenManager(IamTokenOptions options) : base(options)
{
if (string.IsNullOrEmpty(url))
{
if (!string.IsNullOrEmpty(options.IamUrl))
{
url = options.IamUrl;
}
else
{
url = iamDefaultUrl;
}
}

if (!string.IsNullOrEmpty(options.IamApiKey))
{
iamApikey = options.IamApiKey;
}

if (!string.IsNullOrEmpty(options.IamAccessToken))
{
userAccessToken = options.IamAccessToken;
}

if (!string.IsNullOrEmpty(options.IamClientId))
{
iamClientId = options.IamClientId;
}

if (!string.IsNullOrEmpty(options.IamClientSecret))
{
iamClientSecret = options.IamClientSecret;
}

if (string.IsNullOrEmpty(options.IamClientSecret) || string.IsNullOrEmpty(options.IamClientId))
{
iamClientId = "bx";
iamClientSecret = "bx";
Log.Warning("IamTokenManager():", CLIENT_ID_SECRET_WARNING);
}
}

public void SetIamAuthorizationInfo(string IamClientId, string IamClientSecret)
{
iamClientId = IamClientId;
iamClientSecret = IamClientSecret;
if (string.IsNullOrEmpty(iamClientSecret) || string.IsNullOrEmpty(iamClientId))
{
Log.Warning("SetIamAuthorizationInfo():", CLIENT_ID_SECRET_WARNING);
}
}

#region Request Token
/// <summary>
/// Request an IAM token using an API key.
/// </summary>
/// <param name="callback">The request callback.</param>
/// <param name="error"> The request error.</param>
/// <returns></returns>
override protected bool RequestToken(Callback<TokenData> callback)
{
if (callback == null)
throw new ArgumentNullException("successCallback");

RESTConnector connector = new RESTConnector();
connector.URL = url;
if (connector == null)
return false;

RequestIamTokenRequest req = new RequestIamTokenRequest();
req.Callback = callback;
req.HttpMethod = UnityWebRequest.kHttpVerbGET;
req.Headers.Add("Content-type", "application/x-www-form-urlencoded");
req.Headers.Add("Authorization", Utility.CreateAuthorization(iamClientId, iamClientSecret));
req.OnResponse = OnRequestIamTokenResponse;
req.DisableSslVerification = disableSslVerification;
req.Forms = new Dictionary<string, RESTConnector.Form>();
req.Forms["grant_type"] = new RESTConnector.Form("urn:ibm:params:oauth:grant-type:apikey");
req.Forms["apikey"] = new RESTConnector.Form(iamApikey);
req.Forms["response_type"] = new RESTConnector.Form("cloud_iam");

return connector.Send(req);
}

private class RequestIamTokenRequest : RESTConnector.Request
{
public Callback<TokenData> Callback { get; set; }
}

private void OnRequestIamTokenResponse(RESTConnector.Request req, RESTConnector.Response resp)
{
DetailedResponse<TokenData> response = new DetailedResponse<TokenData>();
response.Result = new TokenData();
foreach (KeyValuePair<string, string> kvp in resp.Headers)
{
response.Headers.Add(kvp.Key, kvp.Value);
}
response.StatusCode = resp.HttpResponseCode;

try
{
string json = Encoding.UTF8.GetString(resp.Data);
response.Result = JsonConvert.DeserializeObject<TokenData>(json);
response.Response = json;
}
catch (Exception e)
{
Log.Error("Credentials.OnRequestIamTokenResponse()", "Exception: {0}", e.ToString());
resp.Success = false;
}

if (((RequestIamTokenRequest)req).Callback != null)
((RequestIamTokenRequest)req).Callback(response, resp.Error);
}
#endregion
}

public class IamTokenOptions : JwtTokenOptions
{
private string iamApiKey;
public string IamApiKey
{
get
{
return iamApiKey;
}
set
{
if (!Utility.HasBadFirstOrLastCharacter(value))
{
iamApiKey = value;
}
else
{
throw new IBMException("The credentials shouldn't start or end with curly brackets or quotes. Be sure to remove any {} and \" characters surrounding your credentials");
}
}
}
public string IamAccessToken { get; set; }
public string IamUrl { get; set; }
public string IamClientId { get; set; }
public string IamClientSecret { get; set; }
}
}
154 changes: 154 additions & 0 deletions Authentication/Icp4dTokenManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/**
* Copyright 2019 IBM Corp. 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 IBM.Cloud.SDK.Connection;
using IBM.Cloud.SDK.Utilities;
using System;
using System.Net.Http;
using System.Collections.Generic;
using UnityEngine.Networking;
using Newtonsoft.Json;
using System.Text;
using Utility = IBM.Cloud.SDK.Utilities.Utility;


namespace IBM.Cloud.SDK.Authentication
{
public class Icp4dTokenManager : JwtTokenManager
{
private string username;
private string password;

public Icp4dTokenManager(Icp4dTokenOptions options) : base(options)
{

if (!string.IsNullOrEmpty(options.Url))
{
url = options.Url + "/v1/preauth/validateAuth";
}
else if (string.IsNullOrEmpty(userAccessToken))
{
// url is not needed if the user specifies their own access token
throw new ArgumentNullException("`url` is a required parameter for Icp4dTokenManagerV1");
}

// username and password are required too, unless there's access token
if (!string.IsNullOrEmpty(options.Username))
{
username = options.Username;
}
if (!string.IsNullOrEmpty(options.Password))
{
password = options.Password;
}
if (!string.IsNullOrEmpty(options.AccessToken))
{
userAccessToken = options.AccessToken;
}
disableSslVerification = options.DisableSslVerification;
}

override protected bool RequestToken(Callback<TokenData> callback)
{
if (callback == null)
throw new ArgumentNullException("successCallback");

RESTConnector connector = new RESTConnector();
connector.URL = url;
if (connector == null)
return false;

RequestIcp4dTokenRequest req = new RequestIcp4dTokenRequest();
req.HttpMethod = UnityWebRequest.kHttpVerbGET;
req.Callback = callback;
req.Headers.Add("Content-type", "application/x-www-form-urlencoded");
req.Headers.Add("Authorization", Utility.CreateAuthorization(username, password));
req.OnResponse = OnRequestIcp4dTokenResponse;
req.DisableSslVerification = disableSslVerification;
return connector.Send(req);
}

private class RequestIcp4dTokenRequest : RESTConnector.Request
{
public Callback<TokenData> Callback { get; set; }
}

private void OnRequestIcp4dTokenResponse(RESTConnector.Request req, RESTConnector.Response resp)
{
DetailedResponse<TokenData> response = new DetailedResponse<TokenData>();
response.Result = new TokenData();
foreach (KeyValuePair<string, string> kvp in resp.Headers)
{
response.Headers.Add(kvp.Key, kvp.Value);
}
response.StatusCode = resp.HttpResponseCode;

try
{
string json = Encoding.UTF8.GetString(resp.Data);
response.Result = JsonConvert.DeserializeObject<TokenData>(json);
response.Response = json;
}
catch (Exception e)
{
Log.Error("Credentials.OnRequestIamTokenResponse()", "Exception: {0}", e.ToString());
resp.Success = false;
}
if (((RequestIcp4dTokenRequest)req).Callback != null)
((RequestIcp4dTokenRequest)req).Callback(response, resp.Error);
}
}

public class Icp4dTokenOptions : JwtTokenOptions
{
private string username;
public string Username
{
get { return username; }
set
{
if (!Utility.HasBadFirstOrLastCharacter(value))
{
username = value;
}
else
{
throw new ArgumentException("The username shouldn't start or end with curly brackets or quotes. Be sure to remove any {} and \" characters surrounding your username");
}
}
}

private string password;
public string Password
{
get { return password; }
set
{
if (!Utility.HasBadFirstOrLastCharacter(value))
{
password = value;
}
else
{
throw new ArgumentException("The password shouldn't start or end with curly brackets or quotes. Be sure to remove any {} and \" characters surrounding your password");
}
}
}

public bool DisableSslVerification { get; set; }
}
}
Loading