Initial ...
This commit is contained in:
@@ -0,0 +1,342 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using IdentityModel.Client;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xExceptions.Models;
|
||||
using xIdentityModels.Extensions;
|
||||
using xIdentityModels.Models;
|
||||
using xIds.Extensions;
|
||||
using static IdentityModel.OidcConstants;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
public partial class XIdentityManager
|
||||
{
|
||||
//
|
||||
#region Identity Actions ...
|
||||
/// <summary>
|
||||
/// Request for Discovery Document
|
||||
/// </summary>
|
||||
/// <returns>an instance of <see>DiscoveryDocumentResponse</see></returns>
|
||||
public async Task<DiscoveryDocumentResponse> RequestDiscoveryDocument()
|
||||
{
|
||||
//
|
||||
var httpClient = GetHttpClient();
|
||||
var result = httpClient
|
||||
.GetDiscoveryDocumentAsync(IdentityResourceConfiguration.Authority)
|
||||
.ContinueWith(docTask =>
|
||||
{
|
||||
//
|
||||
httpClient.Dispose();
|
||||
return docTask.Result;
|
||||
});
|
||||
|
||||
//
|
||||
return await result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request AccessToken for Specific XApiScope
|
||||
/// </summary>
|
||||
/// <param name="scope">a member of <see>XApiScope</see></param>
|
||||
/// <returns>an instance of <see>TokenResponse</see></returns>
|
||||
public async Task<IdentityModel.Client.TokenResponse> RequestScopeAccessToken(
|
||||
string scope
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
if (scope.IsNullOrEmpty())
|
||||
{
|
||||
XException.InvalidArgs.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Retrieve Disco Doc ...
|
||||
var discoDoc = await RequestDiscoveryDocument();
|
||||
if (discoDoc.IsError)
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
var request = new ClientCredentialsTokenRequest
|
||||
{
|
||||
Address = discoDoc.TokenEndpoint,
|
||||
GrantType = GrantTypes.ClientCredentials,
|
||||
ClientId = IdentityResourceConfiguration.ClientId,
|
||||
ClientSecret = IdentityResourceConfiguration.ClientSecret,
|
||||
Scope = scope
|
||||
};
|
||||
|
||||
//
|
||||
var httpClient = GetHttpClient();
|
||||
var result = await httpClient
|
||||
.RequestClientCredentialsTokenAsync(request)
|
||||
.ContinueWith(response =>
|
||||
{
|
||||
//
|
||||
httpClient.Dispose();
|
||||
return response.Result;
|
||||
});
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Authenticate a User
|
||||
/// </summary>
|
||||
/// <param name="model">an instance of <see>XLoginRequest</see> class which represent Authentication requirements</param>
|
||||
/// <returns>an instance of <see>TokenResponse</see></returns>
|
||||
public async Task<IdentityModel.Client.TokenResponse> Authenticate(
|
||||
XLoginRequest model
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotNull(model)
|
||||
.AddNotEmpty(
|
||||
model.UserSelectBy,
|
||||
model.Password
|
||||
)
|
||||
.ValidateGroup();
|
||||
|
||||
//
|
||||
// Retrieve Disco Doc ...
|
||||
var discoDoc = await RequestDiscoveryDocument();
|
||||
if (discoDoc.IsError)
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Create Request ...
|
||||
var request = new PasswordTokenRequest
|
||||
{
|
||||
//
|
||||
Address = discoDoc.TokenEndpoint,
|
||||
|
||||
//
|
||||
GrantType = GrantTypes.ClientCredentials,
|
||||
ClientId = IdentityResourceConfiguration.ClientId,
|
||||
ClientSecret = IdentityResourceConfiguration.ClientSecret,
|
||||
|
||||
//
|
||||
UserName = model.UserSelectBy,
|
||||
Password = model.Password,
|
||||
|
||||
//
|
||||
// Pass Device to Request ...
|
||||
Parameters = { { "force", false.ToJSON () }
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
var httpClient = GetHttpClient();
|
||||
var result = await httpClient
|
||||
.RequestPasswordTokenAsync(request)
|
||||
.ContinueWith(response =>
|
||||
{
|
||||
//
|
||||
httpClient.Dispose();
|
||||
return response.Result;
|
||||
});
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Do Login based on XLoginRequest
|
||||
/// </summary>
|
||||
/// <param name="model">an instance of <see>XLoginRequest</see> class which represent Authentication requirements</param>
|
||||
/// <returns>an instance of <see>XLoginResponse</see></returns>
|
||||
public async Task<XLoginResponse> Login(
|
||||
XLoginRequest model
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotNull(model, model.Device)
|
||||
.AddNotEmpty(
|
||||
model.UserSelectBy,
|
||||
model.Password
|
||||
)
|
||||
.ValidateGroup();
|
||||
|
||||
//
|
||||
// Get Token Response ...
|
||||
//
|
||||
// Retrieve Disco Doc ...
|
||||
var discoDoc = await RequestDiscoveryDocument();
|
||||
Logger.LogInformation($"discoDoc: {discoDoc.ToJSON()}");
|
||||
|
||||
if (discoDoc.IsError)
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Create Request ...
|
||||
var request = new PasswordTokenRequest
|
||||
{
|
||||
//
|
||||
Address = discoDoc.TokenEndpoint,
|
||||
|
||||
//
|
||||
GrantType = GrantTypes.ClientCredentials,
|
||||
ClientId = IdentityResourceConfiguration.ClientId,
|
||||
ClientSecret = IdentityResourceConfiguration.ClientSecret,
|
||||
|
||||
//
|
||||
UserName = model.UserSelectBy,
|
||||
Password = model.Password,
|
||||
|
||||
//
|
||||
// Pass Device to Request ...
|
||||
Parameters = { { "force", false.ToJSON () },
|
||||
{ "device", model.Device.ToJSON () },
|
||||
{ "language", model.Language }
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
var httpClient = GetHttpClient();
|
||||
var authResponse = await httpClient
|
||||
.RequestPasswordTokenAsync(request)
|
||||
.ContinueWith(response =>
|
||||
{
|
||||
//
|
||||
httpClient.Dispose();
|
||||
return response.Result;
|
||||
});
|
||||
|
||||
//
|
||||
// Check If Response Has Error ...
|
||||
Logger.LogInformation($"AuthResponse: {authResponse.ToJSON()}");
|
||||
|
||||
//
|
||||
if (authResponse.IsError)
|
||||
{
|
||||
throw authResponse.GetException();
|
||||
}
|
||||
|
||||
//
|
||||
// Create XLoginResponse Model ...
|
||||
var result = authResponse.CreateXLoginResponse();
|
||||
|
||||
//
|
||||
// Get ans Set User Profile ...
|
||||
result.Profile = await GetUserProfileAsync(model.UserSelectBy, model.UserSelectBy);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refresh Tokens
|
||||
/// </summary>
|
||||
/// <param name="model">Authentication Tokens, instance of <see>XTokenResponse</see></param>
|
||||
/// <returns>an instance of <see>XTokenResponse</see></returns>
|
||||
public async Task<XTokenResponse> RefreshTokens(
|
||||
XTokenResponse model
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotNull(model)
|
||||
.AddNotEmpty(
|
||||
model.AccessToken,
|
||||
model.RefreshToken
|
||||
)
|
||||
.ValidateGroup();
|
||||
|
||||
//
|
||||
var authResponse = await RequestDiscoveryDocument()
|
||||
.ContinueWith((discoTask) =>
|
||||
{
|
||||
//
|
||||
var discoDoc = discoTask.Result;
|
||||
if (discoDoc.IsError)
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
using (var httpClient = GetHttpClient())
|
||||
{
|
||||
return httpClient.RequestRefreshTokenAsync(new RefreshTokenRequest
|
||||
{
|
||||
//
|
||||
Address = discoDoc.TokenEndpoint,
|
||||
GrantType = GrantTypes.RefreshToken,
|
||||
ClientId = IdentityResourceConfiguration.ClientId,
|
||||
ClientSecret = IdentityResourceConfiguration.ClientSecret,
|
||||
RefreshToken = model.RefreshToken
|
||||
}).Result;
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Check If Response Has Error ...
|
||||
if (authResponse.IsError)
|
||||
{
|
||||
//
|
||||
XError error = authResponse.ErrorDescription.FromJSON<XError>();
|
||||
throw error.ToException();
|
||||
}
|
||||
|
||||
//
|
||||
// Create XLoginResponse Model ...
|
||||
var result = authResponse.CreateXTokenResponse();
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Requirements ...
|
||||
/// <summary>
|
||||
/// Get an Instance of Http Client
|
||||
/// </summary>
|
||||
/// <returns>an instance of <see>HttpClient</see></returns>
|
||||
public HttpClient GetHttpClient()
|
||||
{
|
||||
//
|
||||
HttpClient httpClient = null;
|
||||
httpClient = new HttpClient();
|
||||
var httpClientHandler = new HttpClientHandler()
|
||||
{
|
||||
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) =>
|
||||
{
|
||||
//
|
||||
Logger.LogInformation(
|
||||
$"SSL Handler: {Environment.NewLine} sender: {sender}, {Environment.NewLine} cert: {cert}, {Environment.NewLine} chain: {chain}, {Environment.NewLine} sslPolicyErrors: {sslPolicyErrors}"
|
||||
);
|
||||
|
||||
//
|
||||
return true;
|
||||
},
|
||||
ClientCertificateOptions = ClientCertificateOption.Manual,
|
||||
};
|
||||
|
||||
//
|
||||
httpClient = new HttpClient(httpClientHandler);
|
||||
|
||||
//
|
||||
return httpClient;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user