angularjsauthenticationasp.net-web-apithinktecture-ident-serverthinktecture-ident-model

AngularJs ASP.NET WebApi Authentication with Thinktecture


I´m trying to make an AngularJs web that sends login and password to an ASP.NET WebApi backend and login this user with Thinktecture.

I have Thinktecture working fine with other project, ASP.NET MVC, using WS-Federation. Now I´m trying to do something similar but changing some components and I can´t make it work.

How can I send from ASP.NET WebApi the userName and password to Thinktecture and get it validated?

using System.Collections.Generic;
using System.IdentityModel.Services;
using System.Web.Http;
using WebApi_AngularJs.Model;

namespace WebApi_AngularJs.Controllers
{
    public class AuthorizationController : ApiController
    {    
        // POST: api/Authorization
        public LoginResponse Post([FromBody]Login data)
        {
            //HOW TO SEND data.user and data.password to ThinkTecture and get
            //response if user valid or not??
            var response = new LoginResponse { access_token = "token", data = "data"};
            return response;
        }   

    }
}

Thank you!


Solution

  • Finally, after reading a lot I have this:

    In AngularJS:

    'use strict';
    app.factory('authService', ['$http', '$q', 'localStorageService', function ($http, $q, localStorageService) {
    
    var serviceBase = 'http://localhost:64346/';
    var authServiceFactory = {};
    
    var _authData = localStorageService.get('authorizationData');
    
    var _authentication = {
        isAuth: _authData != null? true : false,
        userName: _authData != null ? _authData.userName : ""
    };
    
    var _saveRegistration = function (registration) {
    
        _logOut();
    
        return $http.post(serviceBase + 'api/account/register', registration).then(function (response) {
            return response;
        });
    
    };
    
    var _login = function (loginData) {
    
        var data = "grant_type=password&username=" + loginData.userName + "&password=" + loginData.password;
    
        var deferred = $q.defer();
    
        $http.post(serviceBase + 'api/authorization', data, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).success(function (response) {
    
            localStorageService.set('authorizationData', { token: response.access_token, userName: loginData.userName });
    
            _authentication.isAuth = true;
            _authentication.userName = loginData.userName;
    
            deferred.resolve(response);
    
        }).error(function (err, status) {
            _logOut();
            deferred.reject(err);
        });
    
        return deferred.promise;
    
    };
    
    var _logOut = function () {
    
        $http.delete(serviceBase + 'api/authorization').success(function() {
            localStorageService.remove('authorizationData');
    
            _authentication.isAuth = false;
            _authentication.userName = "";
        });
    };
    
    var _fillAuthData = function () {
    
        var authData = localStorageService.get('authorizationData');
        if (authData) {
            _authentication.isAuth = true;
            _authentication.userName = authData.userName;
        }
    
    }
    
    authServiceFactory.saveRegistration = _saveRegistration;
    authServiceFactory.login = _login;
    authServiceFactory.logOut = _logOut;
    authServiceFactory.fillAuthData = _fillAuthData;
    authServiceFactory.authentication = _authentication;
    
    return authServiceFactory;
    }]);
    

    In WebApi:

    using System.Collections.Generic;
    using System.Configuration;
    using System.IdentityModel.Protocols.WSTrust;
    using System.IdentityModel.Services;
    using System.IdentityModel.Tokens;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Security.Claims;
    using System.ServiceModel;
    using System.ServiceModel.Description;
    using System.ServiceModel.Security;
    using System.Web.Http;
    using System.Xml;
    using Thinktecture.IdentityModel.Constants;
    using Thinktecture.IdentityModel.WSTrust;
    using WebApi_AngularJs.Model;
    
    namespace WebApi_AngularJs.Controllers
    {
        public class AuthorizationController : ApiController
        {
            // GET: api/Authorization
            public IEnumerable<string> Get()
            {
                return new string[] { "value1", "value2" };
            }
    
            // GET: api/Authorization/5
            [Authorize]
            public string Get(int id)
            {
                return "value";
            }
    
        // POST: api/Authorization
        public LoginResponse Post([FromBody]Login data)
        {
            var credentials = new ClientCredentials();
            credentials.UserName.UserName = data.UserName;
            credentials.UserName.Password = data.Password;
    
            ServicePointManager.ServerCertificateValidationCallback = (obj, certificate, chain, errors) => true;
    
            var claims = GetClaimsFromIdentityServer(data.UserName, data.Password);
    
            var response = new LoginResponse();
            if (claims != null)
            {
                //All set so now create a SessionSecurityToken
                var token = new SessionSecurityToken(claims)
                {
                    IsReferenceMode = true  //this is 
                    //important.this is how you say create 
                    //the token in reference mode meaning 
                    //your session cookie will contain only a 
                    //referenceid(which is very small) and 
                    //all claims will be stored on the server
                };
                FederatedAuthentication.WSFederationAuthenticationModule.
                SetPrincipalAndWriteSessionToken(token, true);
    
                response = new LoginResponse { access_token = token.Id , data = "data"};
            }
    
            return response;
        }
    
        // PUT: api/Authorization/5
        public void Put(int id, [FromBody]string value)
        {
        }
    
        // DELETE: api/Authorization/
        public void Delete()
        {
            //clear local cookie
            FederatedAuthentication.SessionAuthenticationModule.SignOut();
            FederatedAuthentication.SessionAuthenticationModule.DeleteSessionTokenCookie();
            FederatedAuthentication.WSFederationAuthenticationModule.SignOut(false);
        }
    
        private ClaimsPrincipal GetClaimsFromIdentityServer(string username, string password)
        {
            const string WS_TRUST_END_POINT = "https://srv:4443/issue/wstrust/mixed/username";
            var factory = new System.ServiceModel.Security.WSTrustChannelFactory
            (new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
                                         string.Format(WS_TRUST_END_POINT));
            factory.TrustVersion = TrustVersion.WSTrust13;
            factory.Credentials.UserName.UserName = username;
            factory.Credentials.UserName.Password = password;
    
            var rst = new System.IdentityModel.Protocols.WSTrust.RequestSecurityToken
            {
                RequestType = RequestTypes.Issue,
                KeyType = KeyTypes.Bearer,
                TokenType = TokenTypes.Saml2TokenProfile11,  
                AppliesTo = new EndpointReference
                ("urn:webapisecurity")
            };
            var st = factory.CreateChannel().Issue(rst);
            var token = st as GenericXmlSecurityToken;
            var handlers = FederatedAuthentication.FederationConfiguration.
            IdentityConfiguration.SecurityTokenHandlers;
            var token = handlers.ReadToken(new XmlTextReader
            (new StringReader(token.TokenXml.OuterXml))) as Saml2SecurityToken;
            var identity = handlers.ValidateToken(token).First();
            var principal = new ClaimsPrincipal(identity);
            return principal;
        }
    }
    }
    

    In Web.Config:

    <?xml version="1.0" encoding="utf-8"?>
    <!--
      For more information on how to configure your ASP.NET application, please visit
      http://go.microsoft.com/fwlink/?LinkId=301879
      -->
    <configuration>
      <configSections>
        <section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
        <section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
        <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
        <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
      </configSections>
      <appSettings>
        <add key="webpages:Version" value="3.0.0.0" />
        <add key="webpages:Enabled" value="false" />
        <add key="ClientValidationEnabled" value="true" />
        <add key="UnobtrusiveJavaScriptEnabled" value="true" />
        <add key="ida:FederationMetadataLocation" value="https://srv:4443/FederationMetadata/2007-06/FederationMetadata.xml" />
        <add key="ida:Realm" value="urn:webapisecurity" />
        <add key="ida:AudienceUri" value="urn:webapisecurity" />
        <add key="AppName" value="Web API Security Sample" />
      </appSettings>
      <system.web>
        <compilation debug="true" targetFramework="4.5" />
        <httpRuntime targetFramework="4.5" />
      </system.web>
      <system.webServer>
        <handlers>
          <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
          <remove name="OPTIONSVerbHandler" />
          <remove name="TRACEVerbHandler" />
          <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
        </handlers>
        <modules>
          <add name="WSFederationAuthenticationModule" type="System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
          <add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
        </modules>
        <validation validateIntegratedModeConfiguration="false" />
      </system.webServer>
      <system.identityModel>
        <identityConfiguration>
          <audienceUris>
            <add value="urn:webapisecurity" />
          </audienceUris>
          <claimsAuthorizationManager type="Thinktecture.IdentityServer.Ofi.AuthorizationManager, Thinktecture.IdentityServer.Ofi, Version=1.0.0.0, Culture=neutral" />
          <claimsAuthenticationManager type="Thinktecture.IdentityServer.Ofi.AuthenticationManager, Thinktecture.IdentityServer.Ofi, Version=1.0.0.0, Culture=neutral" />
          <certificateValidation certificateValidationMode="None" />
          <issuerNameRegistry type="System.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
            <trustedIssuers>
              <add thumbprint="489116B0FCF14DF66D47AE272C3B9FD867D0E050" />
            </trustedIssuers>
          </issuerNameRegistry>
        </identityConfiguration>
      </system.identityModel>
      <system.identityModel.services>
        <federationConfiguration>
          <cookieHandler requireSsl="false" />
          <wsFederation passiveRedirectEnabled="true" issuer="https://srv:4443/issue/wsfed" realm="urn:webapisecurity" reply="http://localhost:64346/" requireHttps="false" />
        </federationConfiguration>
      </system.identityModel.services>
      <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
          <dependentAssembly>
            <assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
            <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
            <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
            <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
            <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
            <bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
            <bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
            <bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" />
          </dependentAssembly>
        </assemblyBinding>
      </runtime>
      <entityFramework>
        <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
        <providers>
          <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
        </providers>
      </entityFramework>
    </configuration>
    

    With this, I can see FedAuth cookie set in browser and it makes validation in WebApi too.