Closed MSAppsDev closed 5 years ago
Can you share the Fiddler trace file?
Note WsFed is not appropriate for most API usage, JwtBearer is much better here.
@MSAppsDev fyi your code sample works just fine for me on ADFS 2016.
@rasitha1, i am trying it on adfs 2012.
unfortunately i cannot use ad fs 2016, our Ops team setup ws-federation sign-in emitting jwt on ad fs 2012. Here is the response i am getting after entering credentials in login page.
Looks like WsFederationOptions is initialized with Saml and JWT token handlers however that's the wrong JWT token handler for this RequestedSecurityToken
.
JwtSecurityTokenHandler
expects a plain JWT string and not this BinarySecurityToken
.
So in order to get this working you need to change ADFS (-EnableJWT $false
) and get a regular SAML assertion. Then the sign-in should work.
Does anyone know what's the point in having JwtSecurityTokenHandler
listed in WsFederationOptions
? Is there ever a case where a WS-Fed RSTR can come with RequestedSecurityToken
having a plain JWT?
It seems like a wrapper WsFedJwtSecurityTokenHandler is needed for handling urn:ietf:params:oauth:token-type:jwt
tokens which will extract the base64 JWT from the BinarySecurityToken
and then call the existing JwtSecurityTokenHandler
passing in the actual JWT.
@brentschmaltz
Finally made it work, here is the custom tokenvalidator if someone needs, this parses BinarySecurityToken from Base 64.
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
namespace XXXXX.Web
{
/// <summary>
/// Custom JWT security token validator
/// </summary>
public class WsFedTokenValidator : ISecurityTokenValidator
{
private string _jwtTokenString = null;
private JwtSecurityToken _jwt = null;
private JwtSecurityTokenHandler _jwtHandler = new JwtSecurityTokenHandler();
/// <summary>
/// Returns true if a token can be validated
/// </summary>
/// <returns>true if a token can be validated</returns>
public bool CanValidateToken => throw new NotImplementedException();
/// <summary>
/// Gets and sets the maximum size in bytes that will be processed.
/// </summary>
/// <returns>token size</returns>
public int MaximumTokenSizeInBytes { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
/// <summary>
/// Read JWT token
/// </summary>
/// <param name="securityToken"></param>
/// <returns>tue in case of valid token else false</returns>
public bool CanReadToken(string securityToken)
{
bool response = false;
try
{
if (!string.IsNullOrWhiteSpace(securityToken))
{
var xmlDoc = new System.Xml.XmlDocument();
xmlDoc.LoadXml(securityToken);
if (xmlDoc != null)
{
byte[] tokenBytes = Convert.FromBase64String(xmlDoc.InnerText); //convert the Base64-encoded binary to bytes
_jwtTokenString = Encoding.UTF8.GetString(tokenBytes); //get the original base64-encoded token
if (!string.IsNullOrWhiteSpace(_jwtTokenString))
{
_jwt = _jwtHandler.ReadToken(_jwtTokenString) as JwtSecurityToken;
if (_jwt != null)
{
response = true;
}
}
}
}
return response;
}
finally
{
}
}
/// <summary>
/// Custom security token validation
/// </summary>
/// <param name="securityToken"></param>
/// <param name="validationParameters"></param>
/// <param name="validatedToken"></param>
/// <returns>claims</returns>
public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
{
ClaimsPrincipal principal = null;
SecurityToken token = null;
try
{
if (_jwt != null)
{
principal = _jwtHandler.ValidateToken(_jwtTokenString, validationParameters, out token);
}
validatedToken = token;
return principal;
}
finally
{
}
}
}
}
My .net core api is calling on-Prem ADFS (WS-Federation sign-in protocol) for authentication but context.User is always null after successful login. Below is my Startup.cs
I see that IDP is redirecting to my api and returning wresult with the token value but when i try to access context.User, it is null.
Any pointers on whats wrong here?