Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ADFS 2.0 Windows 2008 R2 Web API

I would like to make a MVC Web Application that talks to a Web API application and use ADFS 2.0 (on Windows 2008 R2) for authentication.

I managed to make the MVC Web Application to authenticate using ADFS.

Q: But I don't know how I should federate my ADFS 2.0 (on Windows 2008 R2) from MVC Web to Web API (assuming they will be deployed in separate servers)?

Browser-ADFS 2.0-Web MVC-Backend Web API

I found a lot of articles on how to do this with WCF or Windows Server 2012 R2, but not with Web API and ADFS 2.0 in Windows Server 2008 R2


Edit, In the end I went for poor man delegation(passing the same token that I receive to the front end to the backend (as it would not make sense to call the adfs again)

FrontEnd -> Call GetToken and put in on the authorization header (I encode it to base64)

public string GetToken()
{
    BootstrapContext bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as BootstrapContext;
    string token = bootstrapContext.Token;

    if (string.IsNullOrEmpty(token))
        token = ToTokenXmlString(bootstrapContext.SecurityToken as SamlSecurityToken);

    return token;
}

string ToTokenXmlString(SecurityToken token)
{
    var genericToken = token as GenericXmlSecurityToken;

    if (genericToken != null)
        return genericToken.TokenXml.OuterXml;

    var handler = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection();
    return ToTokenXmlString(token, handler);
}

string ToTokenXmlString(SecurityToken token, SecurityTokenHandlerCollection handler)
{
    if (!handler.CanWriteToken(token))
        throw new InvalidOperationException("Token type not suppoted");

    var sb = new StringBuilder(128);
    using (StringWriter stringWriter = new StringWriter(sb))
    {
        using (var textWriter = new XmlTextWriter(stringWriter))
        {
            handler.WriteToken(textWriter, token);
            return sb.ToString();
        }
    }
}

Backend-> Parse and validate the token->

public ClaimsIdentity GetIdentityFromToken(string tokenBase64)
{
    if (string.IsNullOrEmpty(tokenBase64))
        return null;

    byte[] tokenByteArray = Convert.FromBase64String(tokenBase64);
    string decodedToken = Encoding.UTF8.GetString(tokenByteArray);

    if (string.IsNullOrWhiteSpace(decodedToken))
        return null;
    try
    {
        var handlers = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.SecurityTokenHandlers;
        SecurityToken token;
        using (StringReader stringReader = new StringReader(decodedToken))
        {
            using (XmlTextReader xmlReader = new XmlTextReader(stringReader))
            {
                token = handlers.ReadToken(xmlReader);
            }
        }

        if (token == null)
            return null;

        return handlers.ValidateToken(token).FirstOrDefault();
    }
    catch (Exception e)
    {
        logger.Error(new AuthenticationException("Error validating the token from ADFS", e));

        return null;
    }
}
like image 364
Petrutiu Mihai Avatar asked Jun 15 '14 15:06

Petrutiu Mihai


1 Answers

I implemented this by passing the bearer token that I received from Adfs into the authorization header of the web api call, and then using the Microsoft.Owin.Security.Jwt nuget package to translate the token into the httpcontext current identity during owin startup in the web api project.

This example uses a jwt token as the bearer token. Choose the proper NuGet package for the token type that you want to use.

Construct the WebRequest in mvc controller

 BootstrapContext bc = ClaimsPrincipal.Current.Identities.First().BootstrapContext as BootstrapContext;
 HttpWebRequest request = WebRequest.Create(ConfigurationManager.AppSettings["ApiUrl"]) as HttpWebRequest;
 request.Method = "GET";
 request.Headers["Authorization"] = "Bearer " + bc.Token;

Owin Startup.cs file in web api Before the app.UseWebApi(config) line.

 app.UseJwtBearerAuthentication(
            new JwtBearerAuthenticationOptions
            {
                AuthenticationMode = AuthenticationMode.Active,
                AllowedAudiences = new[] { ConfigurationSettings.AppSettings["ida:Realm"] },
                IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[] 
                    { 
                        new SymmetricKeyIssuerSecurityTokenProvider(
                            ConfigurationSettings.AppSettings["ida:ValidIssuer"],
                            ConfigurationSettings.AppSettings["ida:SymmetricKey"])
                    },
                Provider = new OAuthBearerAuthenticationProvider
                {
                    OnValidateIdentity = context =>
                    {
                        return System.Threading.Tasks.Task.FromResult<object>(null);
                    }
                }
            });
like image 87
DavidEdwards Avatar answered Oct 24 '22 03:10

DavidEdwards