// This method determines the security token that contains the key material that // the STS should encrypt a session key with in order // for the service the issued token is intended for to be able to extract that session key private static SecurityToken DetermineEncryptingToken(RequestSecurityToken rst) { // If rst is null, we're toast if (rst == null) throw new ArgumentNullException("rst"); // Figure out service URI Uri uri = DetermineEndpointUri(rst); string encryptingTokenSubjectName = (uri == null) ? "localhost" : uri.DnsSafeHost; return GetToken(encryptingTokenSubjectName, StoreName.TrustedPeople, StoreLocation.LocalMachine); }
private static byte[] GetSessionKey(RequestSecurityToken rst, RequestSecurityTokenResponse rstr) { // If rst is null, we're toast if (rst == null) throw new ArgumentNullException("rst"); // If rstr is null, we're toast if (rstr == null) throw new ArgumentNullException("rstr"); // Figure out the keySize int keySize = 256; if (rst.KeySize != 0) keySize = rst.KeySize; Console.WriteLine("Proof key size {0}", keySize); // Figure out whether we're using Combined or Issuer entropy. byte[] sessionKey = null; byte[] senderEntropy = GetSenderEntropy(rst); byte[] issuerEntropy = GetIssuerEntropy(keySize); if (senderEntropy != null) { // Combined entropy Console.WriteLine("Combined Entropy"); sessionKey = RequestSecurityTokenResponse.ComputeCombinedKey(senderEntropy, issuerEntropy, keySize); rstr.IssuerEntropy = new BinarySecretSecurityToken ( issuerEntropy ); rstr.ComputeKey = true; } else { // Issuer-only entropy Console.WriteLine("Issuer-only entropy"); sessionKey = issuerEntropy; rstr.RequestedProofToken = new BinarySecretSecurityToken(sessionKey); } rstr.KeySize = keySize; return sessionKey; }
// The RST message can contain a wsp:AppliesTo which can be used to indicate the service that // the issued token is intended for. This method extracts the URI for that service, if any such // Uri is present in the RST. Otherwise it returns null. private static Uri DetermineEndpointUri(RequestSecurityToken rst) { // If rst is null, we're toast if (rst == null) throw new ArgumentNullException("rst"); EndpointAddress epr = rst.AppliesTo; // If AppliesTo is missing or doesn't contain a 2004/08 or // 2005/10 EPR then the epr local variable will be null in which case we return null. // Otherwise we return the Uri portion of the EPR. return epr == null ? null : epr.Uri; }
private static byte[] GetSenderEntropy(RequestSecurityToken rst) { // If rst is null, we're toast if (rst == null) throw new ArgumentNullException("rst"); SecurityToken senderEntropyToken = rst.RequestorEntropy; byte[] senderEntropy = null; if (senderEntropyToken != null) { BinarySecretSecurityToken bsst = senderEntropyToken as BinarySecretSecurityToken; if (bsst != null) senderEntropy = bsst.GetKeyBytes(); } return senderEntropy; }
private RequestSecurityTokenResponse Issue(RequestSecurityToken rst) { // If rst is null, we're toast if (rst == null) throw new ArgumentNullException("rst"); // Create an RSTR object RequestSecurityTokenResponse rstr = new RequestSecurityTokenResponse(); string tokenType = rst.TokenType; Console.WriteLine("Issue: Request for token type {0}", tokenType); if (tokenType != null && tokenType != "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1") { throw new NotSupportedException("Unsupported token type " + tokenType); } SecurityKey signingKey = issuerToken.SecurityKeys[0]; SecurityKeyIdentifier signingKeyIdentifier = new SecurityKeyIdentifier(issuerToken.CreateKeyIdentifierClause<X509ThumbprintKeyIdentifierClause>()); SecurityKeyIdentifier proofKeyIdentifier = null; if (rst.IsProofKeyAsymmetric()) { throw new NotSupportedException("Public key issuance is not supported"); } // Symmetric proof key Console.WriteLine("Constructing Symmetric Proof Key"); // Construct session key. This is the symmetric key that the client and the service will share. // It actually appears twice in the response message; once for the service and // once for the client. In the former case, it is typically embedded in the issued token, // in the latter case, it is returned in a wst:RequestedProofToken element. byte[] sessionKey = GetSessionKey(rst, rstr); // Get token to use when encrypting key material for the service SecurityToken encryptingToken = DetermineEncryptingToken(rst); // Encrypt the session key for the service GetEncryptedKey(encryptingToken, sessionKey, out proofKeyIdentifier); // Issued tokens are valid for 12 hours by default DateTime effectiveTime = DateTime.Now; DateTime expirationTime = DateTime.Now + new TimeSpan(12, 0, 0); SecurityToken samlToken = CreateSAMLToken(effectiveTime, expirationTime, signingKey, signingKeyIdentifier, proofKeyIdentifier); rstr.RequestedSecurityToken = samlToken; rstr.Context = rst.Context; rstr.TokenType = tokenType; SecurityKeyIdentifierClause samlReference = samlToken.CreateKeyIdentifierClause<SamlAssertionKeyIdentifierClause>(); rstr.RequestedAttachedReference = samlReference; rstr.RequestedUnattachedReference = samlReference; return rstr; }