2013-09-09 4 views
7

я в настоящее время генерации SAML токены ADFS, как это:Как проверить SAML маркер компьютера ADFS

WSTrustChannelFactory factory = null; 
     try 
     { 
      // use a UserName Trust Binding for username authentication 
      factory = new WSTrustChannelFactory(
       new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential), 
       new EndpointAddress("https://adfs.company.com/adfs/services/trust/13/usernamemixed")); 

      factory.TrustVersion = TrustVersion.WSTrust13; 

      factory.Credentials.UserName.UserName = "user"; 
      factory.Credentials.UserName.Password = "pw"; 


      var rst = new RequestSecurityToken 
      { 
       RequestType = RequestTypes.Issue, 
       AppliesTo = new EndpointReference(relyingPartyId), 
       KeyType = KeyTypes.Bearer 
      }; 
      IWSTrustChannelContract channel = factory.CreateChannel(); 
       GenericXmlSecurityToken genericToken = channel.Issue(rst) 
       as  GenericXmlSecurityToken; 
     } 
     finally 
     { 
      if (factory != null) 
      { 
       try 
       { 
        factory.Close(); 
       } 
       catch (CommunicationObjectFaultedException) 
       { 
        factory.Abort(); 
       } 
      } 
     } 

Теперь предположим, что я создаю веб-приложение, которое использует эти маркеры для проверки подлинности. Насколько я знаю, что рабочий процесс должен быть таким:

  • Создать токен
  • клиент получает генерируется маркер (после действительного входа в систему)
  • клиент кэширует маркер
  • клиент использует маркер для следующего входа в систему
  • веб-приложение проверяет токен, не нужно вызывать ADFS

Как я могу проверить, что токен, который представляет клиент, действителен? Нужен ли мне сертификат сервера ADFS для расшифровки токена?

+0

Я всегда мог сохранить маркер к БД, хотя ... – hoetz

ответ

8

Посмотрев на отличной идентичности thinktecture кода сервера (https://github.com/thinktecture/Thinktecture.IdentityServer.v2/tree/master/src/Libraries/Thinktecture.IdentityServer.Protocols/AdfsIntegration) Я извлек решение:

using Newtonsoft.Json; 
using System; 
using System.IdentityModel.Protocols.WSTrust; 
using System.IdentityModel.Selectors; 
using System.IdentityModel.Tokens; 
using System.IO; 
using System.Linq; 
using System.Security.Claims; 
using System.Security.Cryptography.X509Certificates; 
using System.ServiceModel; 
using System.ServiceModel.Security; 
using System.Text; 
using System.Xml; 
using Thinktecture.IdentityModel.Extensions; 
using Thinktecture.IdentityModel.WSTrust; 

namespace SimpleWebConsole 
{ 
internal class ADFS 
{ 
    public static void tokenTest() 
    { 
     string relyingPartyId = "https://party.mycomp.com"; 
     WSTrustChannelFactory factory = null; 
     try 
     { 
      // use a UserName Trust Binding for username authentication 
      factory = new WSTrustChannelFactory(
       new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential), 
       new EndpointAddress("https://adfs.mycomp.com/adfs/services/trust/13/usernamemixed")); 

      factory.TrustVersion = TrustVersion.WSTrust13; 

      factory.Credentials.UserName.UserName = "test"; 
      factory.Credentials.UserName.Password = "test"; 

      var rst = new RequestSecurityToken 
      { 
       RequestType = RequestTypes.Issue, 
       AppliesTo = new EndpointReference(relyingPartyId), 
       KeyType = KeyTypes.Bearer 
      }; 
      IWSTrustChannelContract channel = factory.CreateChannel(); 
      GenericXmlSecurityToken genericToken = channel.Issue(rst) as GenericXmlSecurityToken; //MessageSecurityException -> PW falsch 

      var _handler = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection(); 
      var tokenString = genericToken.ToTokenXmlString(); 

      var samlToken2 = _handler.ReadToken(new XmlTextReader(new StringReader(tokenString))); 

      ValidateSamlToken(samlToken2); 

      X509Certificate2 certificate = null; 

      X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine); 
      store.Open(OpenFlags.ReadOnly); 
      certificate = store.Certificates.Find(X509FindType.FindByThumbprint, "thumb", false)[0]; 

      var jwt=ConvertSamlToJwt(samlToken2, "https://party.mycomp.com", certificate); 

     } 
     finally 
     { 
      if (factory != null) 
      { 
       try 
       { 
        factory.Close(); 
       } 
       catch (CommunicationObjectFaultedException) 
       { 
        factory.Abort(); 
       } 
      } 
     } 
    } 

    public static TokenResponse ConvertSamlToJwt(SecurityToken securityToken, string scope, X509Certificate2 SigningCertificate) 
    { 
     var subject = ValidateSamlToken(securityToken); 


     var descriptor = new SecurityTokenDescriptor 
     { 
      Subject = subject, 
      AppliesToAddress = scope, 
      SigningCredentials = new X509SigningCredentials(SigningCertificate), 
      TokenIssuerName = "https://panav.mycomp.com", 
      Lifetime = new Lifetime(DateTime.UtcNow, DateTime.UtcNow.AddMinutes(10080)) 
     }; 


     var jwtHandler = new JwtSecurityTokenHandler(); 
     var jwt = jwtHandler.CreateToken(descriptor); 


     return new TokenResponse 
     { 
      AccessToken = jwtHandler.WriteToken(jwt), 
      ExpiresIn = 10080 
     }; 
    } 


    public static ClaimsIdentity ValidateSamlToken(SecurityToken securityToken) 
    { 
     var configuration = new SecurityTokenHandlerConfiguration(); 
     configuration.AudienceRestriction.AudienceMode = AudienceUriMode.Never; 
     configuration.CertificateValidationMode = X509CertificateValidationMode.None; 
     configuration.RevocationMode = X509RevocationMode.NoCheck; 
     configuration.CertificateValidator = X509CertificateValidator.None; 

     var registry = new ConfigurationBasedIssuerNameRegistry(); 
     registry.AddTrustedIssuer("thumb", "ADFS Signing - mycomp.com"); 
     configuration.IssuerNameRegistry = registry; 

     var handler = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection(configuration); 
     var identity = handler.ValidateToken(securityToken).First(); 
     return identity; 
    } 

    public class TokenResponse 
    { 
     [JsonProperty(PropertyName = "access_token")] 
     public string AccessToken { get; set; } 


     [JsonProperty(PropertyName = "token_type")] 
     public string TokenType { get; set; } 


     [JsonProperty(PropertyName = "expires_in")] 
     public int ExpiresIn { get; set; } 


     [JsonProperty(PropertyName = "refresh_token")] 
     public string RefreshToken { get; set; } 
    } 

} 
} 
+0

Я также добавил код для преобразования токена в JWT, чтобы его можно было легко использовать в веб-запросах. – hoetz

+0

Был ли это сертификат подписи маркера из ADFS, который вам нужно было хранить локально, чтобы использовать для дешифрования/чтения токена? – Developr

1

Это намного проще! Для веб-сайтов вы используете WIF (при условии, что используете .NET), а затем вы объединяете приложение с ADFS. (Есть мастер, включенный в WIF SDK). Все заботится. Картирование, проверка и т. Д. Осуществляется каркасом. Ваше приложение будет обращаться с пользователями обычным способом: this.User.Name, this.User.IsInRole("admin") и т. Д.

Сценарий задокументирован here.

+2

, что о веб-апи? нет файлов cookie, только заголовки HTTP – hoetz

+0

Зависит от того, кто вызывает API и как реализуется API. Для службы SOAP вы можете использовать SAML и вызов, похожий на ваш пример. Для служб REST вы не часто используете SAML, но что-то более легкое. Это было бы здорово, если бы вы расширили весь сценарий. –