added samples
[windows-sources.git] / sdk / samples / WCFSamples / TechnologySamples / Scenario / Federation / VB / Common / SecurityTokenService.vb
blobf1a717f14d0d22ca909da609e3c0275e1160da12
1 ' Copyright (c) Microsoft Corporation. All Rights Reserved.
3 Imports System
5 Imports System.Collections.ObjectModel
7 Imports System.IdentityModel.Tokens
9 Imports System.Security.Cryptography
10 Imports System.Security.Cryptography.X509Certificates
12 Imports System.ServiceModel
13 Imports System.ServiceModel.Channels
14 Imports System.ServiceModel.Security.Tokens
16 Imports System.Xml
18 Imports Microsoft.VisualBasic
20 Namespace Microsoft.ServiceModel.Samples.Federation
22 ''' <summary>
23 ''' Abstract base class for STS implementations
24 ''' </summary>
25 Public MustInherit Class SecurityTokenService
26 Implements ISecurityTokenService
28 Private stsName As String ' The name of the STS. Used to populate saml:Assertion/@Issuer
29 Private m_issuerToken As SecurityToken ' The SecurityToken used to sign issued tokens
30 Private m_proofKeyEncryptionToken As SecurityToken ' The SecurityToken used to encrypt the proof key in the issued token.
32 ''' <summary>
33 ''' constructor
34 ''' </summary>
35 ''' <param name="stsName">The name of the STS. Used to populate saml:Assertion/@Issuer</param>
36 ''' <param name="token">The X509SecurityToken that the STS uses to sign SAML assertions</param>
37 ''' <param name="targetServiceName">The X509SecurityToken that is used to encrypt the proof key in the SAML token.</param>
38 Protected Sub New(ByVal stsName As String, ByVal issuerToken As X509SecurityToken, ByVal encryptionToken As X509SecurityToken)
40 Me.stsName = stsName
41 Me.m_issuerToken = issuerToken
42 Me.m_proofKeyEncryptionToken = encryptionToken
44 End Sub
46 ''' <summary>
47 ''' The name of the STS.
48 ''' </summary>
49 Protected ReadOnly Property SecurityTokenServiceName() As String
51 Get
53 Return Me.stsName
55 End Get
57 End Property
59 ''' <summary>
60 ''' The SecurityToken used to sign tokens the STS issues.
61 ''' </summary>
62 Protected ReadOnly Property IssuerToken() As SecurityToken
64 Get
66 Return Me.m_issuerToken
68 End Get
70 End Property
72 ''' <summary>
73 ''' The SecurityToken used to encrypt the proof key in the issued token.
74 ''' </summary>
75 Protected ReadOnly Property ProofKeyEncryptionToken() As SecurityToken
77 Get
79 Return Me.m_proofKeyEncryptionToken
81 End Get
83 End Property
85 #Region "Abstract methods"
87 ''' <summary>
88 ''' abstract method for setting up claims in the SAML Token issued by the STS
89 ''' Should be overridden by STS implementations that derive from this base class
90 ''' to set up appropriate claims
91 ''' </summary>
92 Protected MustOverride Function GetIssuedClaims(ByVal requestSecurityToken As RequestSecurityToken) As Collection(Of SamlAttribute)
94 #End Region
96 #Region "Helper Methods"
97 ''' <summary>
98 ''' Validate action header and discard messages with inappropriate headers
99 ''' </summary>
100 Protected Shared Sub EnsureRequestSecurityTokenAction(ByVal message As Message)
102 If message Is Nothing Then
103 Throw New ArgumentNullException("message")
104 End If
106 If message.Headers.Action <> Constants.Trust.Actions.Issue Then
107 Throw New InvalidOperationException([String].Format("Bad or Unsupported Action: {0}", message.Headers.Action))
108 End If
110 End Sub
112 ''' <summary>
113 ''' Helper Method to Create Proof Token. Creates BinarySecretSecuryToken
114 ''' with the requested number of bits of random key material
115 ''' </summary>
116 ''' <param name="keySize">keySize</param>
117 ''' <returns>Proof Token</returns>
118 Protected Shared Function CreateProofToken(ByVal keySize As Integer) As BinarySecretSecurityToken
120 ' Create an array to store the key bytes
121 Dim key() As Byte = New Byte((keySize / 8) - 1) {}
122 ' Create some random bytes
123 Dim random As New RNGCryptoServiceProvider()
124 random.GetNonZeroBytes(key)
125 ' Create a BinarySecretSecurityToken from the random bytes and return it
126 Return New BinarySecretSecurityToken(key)
128 End Function
130 ''' <summary>
131 ''' Helper Method to set up the RSTR
132 ''' </summary>
133 ''' <param name="rst">RequestSecurityToken</param>
134 ''' <param name="keySize">keySize</param>
135 ''' <param name="proofToken">proofToken</param>
136 ''' <param name="samlToken">The SAML Token to be issued</param>
137 ''' <returns>RequestSecurityTokenResponse</returns>
138 Protected Shared Function GetRequestSecurityTokenResponse(ByVal requestSecurityToken As RequestSecurityToken, ByVal keySize As Integer, ByVal proofToken As SecurityToken, ByVal samlToken As SecurityToken, ByVal senderEntropy() As Byte, ByVal stsEntropy() As Byte) As RequestSecurityTokenResponse
140 ' Create an uninitialized RequestSecurityTokenResponse object and set the various properties
141 Dim rstr As New RequestSecurityTokenResponse()
142 rstr.TokenType = Constants.SamlTokenTypeUri
143 rstr.RequestedSecurityToken = samlToken
144 rstr.RequestedUnattachedReference = samlToken.CreateKeyIdentifierClause(Of SamlAssertionKeyIdentifierClause)()
145 rstr.RequestedAttachedReference = samlToken.CreateKeyIdentifierClause(Of SamlAssertionKeyIdentifierClause)()
146 rstr.Context = requestSecurityToken.Context
147 rstr.KeySize = keySize
149 ' If sender provided entropy then use combined entropy so set the IssuerEntropy
150 If senderEntropy IsNot Nothing Then
152 rstr.IssuerEntropy = New BinarySecretSecurityToken(stsEntropy)
153 rstr.ComputeKey = True
155 Else
157 ' Issuer entropy only...
158 rstr.RequestedProofToken = proofToken
160 End If
162 Return rstr
164 End Function
165 #End Region
167 ''' <summary>
168 ''' Virtual method for ProcessRequestSecurityToken
169 ''' Should be overridden by STS implementations that derive from this base class
170 ''' </summary>
171 Public Overridable Function ProcessRequestSecurityToken(ByVal msg As Message) As Message Implements ISecurityTokenService.ProcessRequestSecurityToken
173 ' Check for appropriate action header
174 EnsureRequestSecurityTokenAction(msg)
176 ' Extract the MessageID from the request message
177 Dim requestMessageID As UniqueId = msg.Headers.MessageId
178 If requestMessageID Is Nothing Then
179 Throw New InvalidOperationException("The request message does not have a message ID.")
180 End If
182 ' Get the RST from the message
183 Dim rst As RequestSecurityToken = RequestSecurityToken.CreateFrom(msg.GetReaderAtBodyContents())
185 ' Set up the claims we are going to issue
186 Dim samlAttributes As Collection(Of SamlAttribute) = GetIssuedClaims(rst)
188 ' get the key size, default to 192
189 Dim keySize As Integer = IIf((rst.KeySize <> 0), rst.KeySize, 192)
191 ' Create proof token
192 ' Get requester entropy, if any
193 Dim senderEntropy() As Byte = Nothing
194 Dim entropyToken As SecurityToken = rst.RequestorEntropy
195 If entropyToken IsNot Nothing Then
197 senderEntropy = (DirectCast(entropyToken, BinarySecretSecurityToken)).GetKeyBytes()
199 End If
201 Dim key() As Byte = Nothing
202 Dim stsEntropy() As Byte = Nothing
204 ' If sender provided entropy, then use combined entropy
205 If senderEntropy IsNot Nothing Then
207 ' Create an array to store the entropy bytes
208 stsEntropy = New Byte((keySize \ 8) - 1) {}
209 ' Create some random bytes
210 Dim random As New RNGCryptoServiceProvider()
211 random.GetNonZeroBytes(stsEntropy)
212 ' Compute the combined key
213 key = RequestSecurityTokenResponse.ComputeCombinedKey(senderEntropy, stsEntropy, keySize)
215 Else
217 ' Issuer entropy only...
218 ' Create an array to store the entropy bytes
219 key = New Byte((keySize \ 8) - 1) {}
220 ' Create some random bytes
221 Dim random As New RNGCryptoServiceProvider()
222 random.GetNonZeroBytes(key)
224 End If
226 ' Create a BinarySecretSecurityToken to be the proof token, based on the key material
227 ' in key. The key is the combined key in the combined entropy case, or the issuer entropy
228 ' otherwise
229 Dim proofToken As New BinarySecretSecurityToken(key)
231 ' Create a SAML token, valid for around 10 hours
232 Dim samlToken As SamlSecurityToken = SamlTokenCreator.CreateSamlToken(Me.stsName, proofToken, Me.IssuerToken, Me.ProofKeyEncryptionToken, New SamlConditions(DateTime.UtcNow - TimeSpan.FromMinutes(5), DateTime.UtcNow + TimeSpan.FromHours(10)), samlAttributes)
234 ' Set up RSTR
235 Dim rstr As RequestSecurityTokenResponse = GetRequestSecurityTokenResponse(rst, keySize, proofToken, samlToken, senderEntropy, stsEntropy)
237 ' Create a message from the RSTR
238 Dim rstrMessage As Message = Message.CreateMessage(msg.Version, Constants.Trust.Actions.IssueReply, rstr)
240 ' Set RelatesTo of response message to MessageID of request message
241 rstrMessage.Headers.RelatesTo = requestMessageID
243 ' Return the create message
244 Return rstrMessage
246 End Function
248 End Class
250 End Namespace