Cercar en aquest blog

22/4/10

Proveïdor d’Identitats: Un exemple per entendre-ho tot (V)


(PART IV)
Per implementar la negociacio amb el STS i el accés al servei, primer ens crearem un a llibreria en C# i anomenada IDP i li posarem aquesta classe dins: 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IdentityModel.Tokens;
using System.ServiceModel;
using Microsoft.IdentityModel.Protocols.WSTrust;
using System.ServiceModel.Security;

namespace IDP
{
    public static class EndPoints
    {
        public static string baseUri = "http://[idphost]/adfs/services/";
        public static string SSLbaseUri = "https://[idphost]/adfs/services/";
        
        public  static SecurityToken GetTokenFrom_trust_13_usernamemixed(string username, string password, string appliesTo, out RequestSecurityTokenResponse rsts)
        {
            string adrecaSTS = "trust/13/usernamemixed";

            WS2007HttpBinding binding = new WS2007HttpBinding();

            binding.Security.Message.EstablishSecurityContext = false;
            binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
            binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
            binding.Security.Mode = SecurityMode.TransportWithMessageCredential; //https




            WSTrustChannelFactory trustChannelFactory = new WSTrustChannelFactory(binding, new EndpointAddress(SSLbaseUri + adrecaSTS));
            trustChannelFactory.TrustVersion = TrustVersion.WSTrust13;
            trustChannelFactory.Credentials.UserName.UserName = username;
            trustChannelFactory.Credentials.UserName.Password = password;
            trustChannelFactory.ConfigureChannelFactory();

            WSTrustChannel tokenClient = (WSTrustChannel)trustChannelFactory.CreateChannel();


            //create a token issuance issuance
            RequestSecurityToken rst = new RequestSecurityToken(WSTrust13Constants.RequestTypes.Issue);
            //Relying Party’s identifier
            rst.AppliesTo = new EndpointAddress(appliesTo);
            //call ADFS STS
            SecurityToken token = tokenClient.Issue(rst, out rsts);

            return token;
        }
        
        public static SecurityToken GetTokenFrom_trust_13_windows(string appliesTo, out RequestSecurityTokenResponse rsts)
        {
            string adrecaSTS = "trust/13/windows";

            WS2007HttpBinding binding = new WS2007HttpBinding();

            binding.Security.Message.EstablishSecurityContext = false;
            binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
            binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
            binding.Security.Mode = SecurityMode.Message;
            binding.Security.Message.NegotiateServiceCredential = true;




            WSTrustChannelFactory trustChannelFactory = new WSTrustChannelFactory(binding, new EndpointAddress(baseUri + adrecaSTS));
            trustChannelFactory.TrustVersion = TrustVersion.WSTrust13;
            trustChannelFactory.ConfigureChannelFactory();

            WSTrustChannel tokenClient = (WSTrustChannel)trustChannelFactory.CreateChannel();


            //create a token issuance issuance
            RequestSecurityToken rst = new RequestSecurityToken(WSTrust13Constants.RequestTypes.Issue);
            //Relying Party’s identifier
            rst.AppliesTo = new EndpointAddress(appliesTo);
            //call ADFS STS
            SecurityToken token = tokenClient.Issue(rst, out rsts);

            return token;
        }

  
    }
}


Aquesta classe ens ajuda a obtenir tokens del STS per un servei en concret. El primer mètode, a partir d’unes credencials entrades per l’usuari, i el segon utilitzan les credencials del usuari loginat al SO (usuari Windows).


I ara, per tal de facilitar la creació de clients de Serveis (Agents de servei), que puguin actuar amb o sense delegació, utilitzarem una altre llibreria que ens facilitarà la feina. Aquesta la farem en VB.Net i li direm STS. Dins hi posarem la següent classe. Hem de fer les referències.

Imports System.IdentityModel.Tokens
Imports System.ServiceModel
Imports System.ServiceModel.Description
Imports Microsoft.IdentityModel.Protocols.WSTrust
Imports System.ServiceModel.Channels
Imports System.ServiceModel.Security
Imports System.ServiceModel.Security.Tokens
Imports System.Text

Public Class STSRPClient(Of T)
    Implements IDisposable
#Region "Members"
    Private _st As SecurityToken
    Private _factory As ChannelFactory(Of T)
#End Region
    ''' 
    ''' Contructor per generar Client a partir del fitxer de configuració
    ''' 
    ''' 
''' 
''' 
    Sub New(ByVal st As SecurityToken, ByVal bindingConfiguration As String)
        Create(st, bindingConfiguration)
    End Sub
  
    Private Sub Create(ByVal st As SecurityToken, ByVal bindingconfiguration As String)
        Me._st = st
        _factory = New ChannelFactory(Of T)(bindingconfiguration)
        _factory.ConfigureChannelFactory()
    End Sub

    Public Sub Close()
        _factory.Close()
    End Sub

    Public ReadOnly Property Client As T
        Get
            Return _factory.CreateChannelWithIssuedToken(_st)
        End Get
    End Property
    Public ReadOnly Property ClientActAs As T
        Get
            Return _factory.CreateChannelActingAs(_st)
        End Get
    End Property

#Region "IDisposable Support"
    Private disposedValue As Boolean ' To detect redundant calls

    ' IDisposable
    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' TODO: dispose managed state (managed objects).
            End If
            If Me._factory.State <> CommunicationState.Closed Then
                _factory.Close()
            End If
            _st = Nothing
            ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
            ' TODO: set large fields to null.
        End If
        Me.disposedValue = True
    End Sub

    ' TODO: override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources.
    'Protected Overrides Sub Finalize()
    '    ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
    '    Dispose(False)
    '    MyBase.Finalize()
    'End Sub

    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

End Class


Un cop compilades, farem les referències a aquestes en l’aplicació client.


  1. Obtenir token per l’usuari
  2. Crear client amb el token
  3. Invocar Servei
  4. Escriure el resultat

Imports System.IdentityModel.Tokens
Imports Microsoft.IdentityModel.Protocols.WSTrust

Public Class Form1

    Private Sub BInvoke_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BInvoke.Click

        Dim adrecaservei As String = "http://localhost/Front_End_Service/Service.svc"

        ' App.config - Nom de la configuració del binding del client
        Dim conf As String = "WS2007FederationHttpBinding_IService"


        ' Primer hem d'obtenir un token de seguretat del IDP pel servei

        Dim rsts As New RequestSecurityTokenResponse
        Dim st As SecurityToken = IDP.EndPoints.GetTokenFrom_trust_13_usernamemixed(Me.TxtUser.Text, Me.TxtPwd.Text, adrecaservei, rsts)

        ' Un cop el tenim em de fer-lo servir per accedir-hi i invocar les seves operacions

        Dim clirp As New STS.STSRPClient(Of Front_End_Service.IServiceChannel)(st, conf)
        Dim client As Front_End_Service.IServiceChannel = clirp.Client

        Dim response As String = client.GetDataUserName()

        clirp.Close()
        clirp.Dispose()


        Me.TextBox1.AppendText(response + vbNewLine)

    End Sub
End Class



Diagrama de seqüències del event del botó.

Ara ja podem compilar i provar. De moment només invoquem el primer servei.



Invocació amb unes credencials incorrectes

 
Invocació amb credencials correctes.