sandya_116
asked on
ASP.NET CORE 3.1 - generate bearer token with WS-Federation
I have code similar to the link in https://docs.microsoft.com/en-us/aspnet/core/security/authentication/ws-federation?view=aspnetcore-2.1 to do Single Sign On using WS-Federation. I have code below to generate bearer token for .NET Framework but this code is not working in .NET Core 3.1. Can somebody please help me with similar code for .NET Core? Thank you.
ClaimsPrincipal claimsPrincipal = Thread.CurrentPrincipal as ClaimsPrincipal;
var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as System.IdentityModel.Tokens.BootstrapContext;
System.IdentityModel.Tokens.BootstrapContext context = (System.IdentityModel.Tokens.BootstrapContext)ClaimsPrincipal.Current.Identities.First().BootstrapContext;
SecurityToken token = context.SecurityToken;
if (context.SecurityToken == null)
{
var handlers = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.SecurityTokenHandlers;
token = handlers.ReadToken(new XmlTextReader(new StringReader(context.Token)));
}
GenericXmlSecurityToken xmlTokenOauthToken = (GenericXmlSecurityToken)ProvisionOAuth2SecurityToken(token, PF_IP_STS_Endpoint, appliesToOauth, oauthViaTokenType);
if (xmlTokenOauthToken != null && xmlTokenOauthToken.TokenXml.HasAttributes)
{
string decodedStr = Encoding.UTF8.GetString(Convert.FromBase64String(xmlTokenOauthToken.TokenXml.InnerText));
Dictionary<string, object> values =
JsonConvert.DeserializeObject<Dictionary<string, object>>(decodedStr);
strToken = values["access_token"] as string;
Console.WriteLine(string.Format("BearerToken: Access Token {0} ", strToken));
}
private static SecurityToken ProvisionOAuth2SecurityToken(SecurityToken foreignToken, string RP_Endpoint, string appliesTo, string localTokeType, string keyType = KeyTypes.Bearer)
{
if (String.IsNullOrWhiteSpace(RP_Endpoint)) throw new ArgumentNullException("RP_Endpoint");
Binding binding = null;
var WsHttpBinding = new WS2007FederationHttpBinding(WSFederationHttpSecurityMode.TransportWithMessageCredential);
WsHttpBinding.Security.Message.EstablishSecurityContext = false;
WsHttpBinding.Security.Message.NegotiateServiceCredential = false;
WsHttpBinding.Security.Message.IssuedKeyType = SecurityKeyType.BearerKey;
binding = WsHttpBinding;
EndpointAddress endpoint = new EndpointAddress(new Uri(RP_Endpoint));
using (var factory = new WSTrustChannelFactory(binding, endpoint) { TrustVersion = TrustVersion.WSTrust13 })
{
factory.Credentials.SupportInteractive = false;
factory.Credentials.UseIdentityConfiguration = true;
RequestSecurityToken RST = new RequestSecurityToken()
{
AppliesTo = new EndpointReference(appliesTo),
RequestType = RequestTypes.Issue,
TokenType = localTokeType,
KeyType = null
};
RequestSecurityTokenResponse RSTR_OAuthBearerToken;
IWSTrustChannelContract channel = factory.CreateChannelWithIssuedToken(foreignToken);
GenericXmlSecurityToken xmltoken = null;
CancellationTokenSource canceltokensource = new CancellationTokenSource();
int noofSeconds = 3;
try
{
string timeoutServiceCallValue = "";
if (!string.IsNullOrEmpty(timeoutServiceCallValue))
{
noofSeconds = Convert.ToInt32(timeoutServiceCallValue);
}
canceltokensource.CancelAfter(TimeSpan.FromSeconds(noofSeconds));
var token = canceltokensource.Token;
Task task = Task.Run(() =>
{
xmltoken = channel.Issue(RST, out RSTR_OAuthBearerToken) as GenericXmlSecurityToken;
}, token);
task.Wait(token);
if ((task.Status == TaskStatus.Faulted || task.Exception != null))
{
Console.WriteLine("Class1", "Exception occurred while getting OAuth2SecurityToken {0} \n {1} \n {2}", HttpContext.Current.Request.RawUrl, task.Exception.InnerException, task.Exception.StackTrace);
}
}
catch (TaskCanceledException taskex)
{
}
catch (OperationCanceledException waitex)
{
}
catch (AggregateException aex)
{
}
catch (Exception ex)
{
}
finally
{
canceltokensource.Dispose();
}
return xmltoken;
}
}
ClaimsPrincipal claimsPrincipal = Thread.CurrentPrincipal as ClaimsPrincipal;
var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as System.IdentityModel.Tokens.BootstrapContext;
System.IdentityModel.Tokens.BootstrapContext context = (System.IdentityModel.Tokens.BootstrapContext)ClaimsPrincipal.Current.Identities.First().BootstrapContext;
SecurityToken token = context.SecurityToken;
if (context.SecurityToken == null)
{
var handlers = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.SecurityTokenHandlers;
token = handlers.ReadToken(new XmlTextReader(new StringReader(context.Token)));
}
GenericXmlSecurityToken xmlTokenOauthToken = (GenericXmlSecurityToken)ProvisionOAuth2SecurityToken(token, PF_IP_STS_Endpoint, appliesToOauth, oauthViaTokenType);
if (xmlTokenOauthToken != null && xmlTokenOauthToken.TokenXml.HasAttributes)
{
string decodedStr = Encoding.UTF8.GetString(Convert.FromBase64String(xmlTokenOauthToken.TokenXml.InnerText));
Dictionary<string, object> values =
JsonConvert.DeserializeObject<Dictionary<string, object>>(decodedStr);
strToken = values["access_token"] as string;
Console.WriteLine(string.Format("BearerToken: Access Token {0} ", strToken));
}
private static SecurityToken ProvisionOAuth2SecurityToken(SecurityToken foreignToken, string RP_Endpoint, string appliesTo, string localTokeType, string keyType = KeyTypes.Bearer)
{
if (String.IsNullOrWhiteSpace(RP_Endpoint)) throw new ArgumentNullException("RP_Endpoint");
Binding binding = null;
var WsHttpBinding = new WS2007FederationHttpBinding(WSFederationHttpSecurityMode.TransportWithMessageCredential);
WsHttpBinding.Security.Message.EstablishSecurityContext = false;
WsHttpBinding.Security.Message.NegotiateServiceCredential = false;
WsHttpBinding.Security.Message.IssuedKeyType = SecurityKeyType.BearerKey;
binding = WsHttpBinding;
EndpointAddress endpoint = new EndpointAddress(new Uri(RP_Endpoint));
using (var factory = new WSTrustChannelFactory(binding, endpoint) { TrustVersion = TrustVersion.WSTrust13 })
{
factory.Credentials.SupportInteractive = false;
factory.Credentials.UseIdentityConfiguration = true;
RequestSecurityToken RST = new RequestSecurityToken()
{
AppliesTo = new EndpointReference(appliesTo),
RequestType = RequestTypes.Issue,
TokenType = localTokeType,
KeyType = null
};
RequestSecurityTokenResponse RSTR_OAuthBearerToken;
IWSTrustChannelContract channel = factory.CreateChannelWithIssuedToken(foreignToken);
GenericXmlSecurityToken xmltoken = null;
CancellationTokenSource canceltokensource = new CancellationTokenSource();
int noofSeconds = 3;
try
{
string timeoutServiceCallValue = "";
if (!string.IsNullOrEmpty(timeoutServiceCallValue))
{
noofSeconds = Convert.ToInt32(timeoutServiceCallValue);
}
canceltokensource.CancelAfter(TimeSpan.FromSeconds(noofSeconds));
var token = canceltokensource.Token;
Task task = Task.Run(() =>
{
xmltoken = channel.Issue(RST, out RSTR_OAuthBearerToken) as GenericXmlSecurityToken;
}, token);
task.Wait(token);
if ((task.Status == TaskStatus.Faulted || task.Exception != null))
{
Console.WriteLine("Class1", "Exception occurred while getting OAuth2SecurityToken {0} \n {1} \n {2}", HttpContext.Current.Request.RawUrl, task.Exception.InnerException, task.Exception.StackTrace);
}
}
catch (TaskCanceledException taskex)
{
}
catch (OperationCanceledException waitex)
{
}
catch (AggregateException aex)
{
}
catch (Exception ex)
{
}
finally
{
canceltokensource.Dispose();
}
return xmltoken;
}
}
ASKER
What I meant to say is I followed that article for SSO and that is working fine in ASP.NET Core 3.1. The part where I am stuck is at getting the Bearer token. The code I have pasted is sample code that worked for .NET Framework 4.8 but I need similar code for .NET Core 3.1. Thanks.
1) Generate a public / private key from here: https://travistidwell.com/jsencrypt/demo/
On the service side:
On the service side:
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using ThirdParty.BouncyCastle.OpenSsl;
//read the private key file location
using (TextReader stream = System.IO.File.OpenText(PRIVATEKEYLOCATION))
{
// read the private keyfile
var reader = new PemReader(stream);
//get the key
var key = new RsaSecurityKey(reader.ReadPrivatekey());
//issue claims, which can be adjusted
var claims = new List<Claim>()
{
new Claim(ClaimTypes.Name, user.FirstName),
new Claim(ClaimTypes.GivenName, user.LastName),
new Claim(ClaimTypes.WindowsAccountName, user.Username),
new Claim("DisplayName", (user.FirstName ?? string.Empty) + " " + (user.LastName ?? string.Empty)),
new Claim(ClaimTypes.Email, user.Email)
};
//create the token
var token = new SecurityTokenDescriptor()
{
Expires = DateTime.UtcNow.AddMinutes(timeout_min),
Issuer = issuer_URL,
Audience = audience_URL,
Subject = new ClaimsIdentity(claims),
Claims = claims.ToDictionary(group => group.Type, group => (object)group.Value),
IssuedAt = now,
SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.RsaSha256)
};
var tokenHandler = new JwtSecurityTokenHandler();
//sign the token
string token = tokenHandler.CreateEncodedJwt(token);
//token can now be returned to the client
This question needs an answer!
Become an EE member today
7 DAY FREE TRIALMembers can start a 7-Day Free trial then enjoy unlimited access to the platform.
View membership options
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
https://docs.microsoft.com/en-us/aspnet/core/security/authentication/ws-federation?view=aspnetcore-3.1