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 ...
///
/// Request for Discovery Document
///
/// an instance of DiscoveryDocumentResponse
public async Task RequestDiscoveryDocument()
{
//
var httpClient = GetHttpClient();
var result = httpClient
.GetDiscoveryDocumentAsync(IdentityResourceConfiguration.Authority)
.ContinueWith(docTask =>
{
//
httpClient.Dispose();
return docTask.Result;
});
//
return await result;
}
///
/// Request AccessToken for Specific XApiScope
///
/// a member of XApiScope
/// an instance of TokenResponse
public async Task 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;
}
///
/// Authenticate a User
///
/// an instance of XLoginRequest class which represent Authentication requirements
/// an instance of TokenResponse
public async Task 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;
}
///
/// Do Login based on XLoginRequest
///
/// an instance of XLoginRequest class which represent Authentication requirements
/// an instance of XLoginResponse
public async Task 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;
}
///
/// Refresh Tokens
///
/// Authentication Tokens, instance of XTokenResponse
/// an instance of XTokenResponse
public async Task 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();
throw error.ToException();
}
//
// Create XLoginResponse Model ...
var result = authResponse.CreateXTokenResponse();
//
return result;
}
#endregion
//
#region Requirements ...
///
/// Get an Instance of Http Client
///
/// an instance of HttpClient
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
}
}