< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.IdentityModel.Tokens.EncryptedSecurityTokenHandler
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/IdentityModel/Tokens/EncryptedSecurityTokenHandler.cs
Line coverage
6%
Covered lines: 6
Uncovered lines: 84
Coverable lines: 90
Total lines: 342
Line coverage: 6.6%
Branch coverage
0%
Covered branches: 0
Total branches: 50
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.cctor()100%11100%
.ctor()100%11100%
CanReadKeyIdentifierClause(...)0%220%
CanReadToken(...)100%110%
ReadToken(...)0%24240%
ReadKeyIdentifierClause(...)0%440%
DebugEncryptedTokenClearText(...)100%110%
GetTokenTypeIdentifiers()100%11100%
WriteToken(...)0%12120%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/IdentityModel/Tokens/EncryptedSecurityTokenHandler.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System;
 5using System.Diagnostics;
 6using CoreWCF.IdentityModel.Selectors;
 7using System.IO;
 8using System.Security.Cryptography;
 9using CoreWCF.Security;
 10using System.Text;
 11using System.Xml;
 12
 13namespace CoreWCF.IdentityModel.Tokens
 14{
 15    /// <summary>
 16    /// Token handler for an encrypted <see cref="SecurityToken"/> type.
 17    /// </summary>
 18    public class EncryptedSecurityTokenHandler : SecurityTokenHandler
 19    {
 120        private static readonly string[] s_tokenTypeIdentifiers = new string[] { null };
 21        private SecurityTokenSerializer _keyInfoSerializer;
 422        private readonly object _syncObject = new object();
 23
 24        /// <summary>
 25        /// Create an instance of <see cref="EncryptedSecurityTokenHandler"/>
 26        /// </summary>
 427        public EncryptedSecurityTokenHandler()
 28        {
 429        }
 30
 31        /// <summary>
 32        /// Indicates if the current XML element is pointing to a KeyIdentifierClause that
 33        /// can be de-serialized by this instance.
 34        /// </summary>
 35        /// <param name=nameof(reader)>An XML reader positioned at the start element.
 36        /// The reader should not be advanced.</param>
 37        /// <returns>true if the XML reader is positioned at an EncryptedKey xml element
 38        /// as defined in section 3.5.1 of 'http://www.w3.org/TR/2002/REC-xmlenc-core-20021210'.</returns>
 39        /// <exception cref="ArgumentNullException">The <paramref name=nameof(reader)/> is null.</exception>
 40        public override bool CanReadKeyIdentifierClause(XmlReader reader)
 41        {
 042            if (reader == null)
 43            {
 044                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(reader));
 45            }
 46
 47            // <EncryptedKey>
 048            return reader.IsStartElement(XmlEncryptionConstants.Elements.EncryptedKey, XmlEncryptionConstants.Namespace)
 49        }
 50
 51        /// <summary>
 52        /// Returns true if the reader is pointing to an EncryptedData element.
 53        /// </summary>
 54        /// <param name=nameof(reader)>The reader positioned at a security token.</param>
 55        /// <returns>true if the reader is positioned at EncryptedData else false.</returns>
 56        /// <remarks>Does not move the reader when returning false.</remarks>
 057        public override bool CanReadToken(XmlReader reader) => EncryptedDataElement.CanReadFrom(reader);
 58
 59        /// <summary>
 60        /// Overrides the base CanWriteToken and returns true always.
 61        /// </summary>
 062        public override bool CanWriteToken => true;
 63
 64        /// <summary>
 65        /// Gets or Sets a SecurityTokenSerializers that will be used to serialize and deserializer
 66        /// SecurtyKeyIdentifier of the &lt;xenc:EncryptedData> element.
 67        /// </summary>
 68        /// <exception cref="ArgumentNullException">Input parameter 'value' is null.</exception>
 69        public SecurityTokenSerializer KeyInfoSerializer
 70        {
 71            get
 72            {
 073                if ( _keyInfoSerializer == null )
 74                {
 075                    lock ( _syncObject )
 76                    {
 077                        if ( _keyInfoSerializer == null )
 78                        {
 079                            SecurityTokenHandlerCollection sthc = (ContainingCollection != null) ?
 080                            ContainingCollection : throw new NotSupportedException();
 081                            _keyInfoSerializer = new SecurityTokenSerializerAdapter(sthc);
 82                        }
 083                    }
 84                }
 85
 086                return _keyInfoSerializer;
 87            }
 88            set
 89            {
 090                _keyInfoSerializer = value ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(va
 091            }
 92        }
 93
 94        /// <summary>
 95        /// Reads the encrypted security token.
 96        /// </summary>
 97        /// <param name=nameof(reader)>The reader from which to read the token.</param>
 98        /// <returns>An instance of <see cref="SecurityToken"/>.</returns>
 99        /// <exception cref="ArgumentNullException">Input parameter 'reader' is null.</exception>
 100        /// <exception cref="InvalidOperationException">One of the properties 'Configuration' or 'Configuration.ServiceT
 101        /// <exception cref="SecurityTokenException">A <see cref="SecurityKeyIdentifier"/> is not found inside the xml p
 102        /// <exception cref="EncryptedTokenDecryptionFailedException">The <see cref="SecurityKeyIdentifier"/> found insi
 103        /// <exception cref="SecurityTokenException">The <see cref="SecurityKeyIdentifier"/> is not a <see cref="Symmetr
 104        /// <exception cref="InvalidOperationException">The ContainingCollection (<see cref="SecurityTokenHandlerCollect
 105        public override SecurityToken ReadToken(XmlReader reader)
 106        {
 0107            if (null == reader)
 108            {
 0109                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(reader));
 110            }
 111
 0112            if (Configuration == null)
 113            {
 0114                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInvalidOperation(SR.Format(SR.ID4274));
 115            }
 116
 0117            if (Configuration.ServiceTokenResolver == null)
 118            {
 0119                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInvalidOperation(SR.Format(SR.ID4276));
 120            }
 121
 122            //
 123            // Read the encrypted data element
 124            //
 0125            EncryptedDataElement encryptedData = new EncryptedDataElement(KeyInfoSerializer);
 0126            encryptedData.ReadXml(XmlDictionaryReader.CreateDictionaryReader(reader));
 127
 128            //
 129            // All the clauses in a keyinfo must identify the same key, so we
 130            // can try each clause in turn and stop when one resolves.
 131            //
 0132            SecurityKey decryptionKey = null;
 0133            foreach (SecurityKeyIdentifierClause clause in encryptedData.KeyIdentifier)
 134            {
 0135                Configuration.ServiceTokenResolver.TryResolveSecurityKey(clause, out decryptionKey);
 136
 0137                if (null != decryptionKey)
 138                {
 0139                    break;
 140                }
 141            }
 142
 143            //
 144            // Try to use the SKI to create the key instead.
 145            //
 0146            if (decryptionKey == null && encryptedData.KeyIdentifier.CanCreateKey)
 147            {
 0148                decryptionKey = encryptedData.KeyIdentifier.CreateKey();
 149            }
 150
 151            //
 152            // Fail if none of the clauses resolved or ski itself cannot create key.
 153            //
 0154            if (null == decryptionKey)
 155            {
 156                EncryptedKeyIdentifierClause encryptedKeyClause;
 0157                if (encryptedData.KeyIdentifier.TryFind<EncryptedKeyIdentifierClause>(out encryptedKeyClause))
 158                {
 159                    //
 160                    // System.IdentityModel.Tokens.EncryptedKeyIdentifierClause.ToString() does not print out
 161                    // very good information except the cipher data in this case. We have worked around that
 162                    // by using the token serializer to serialize the key identifier clause again.
 163                    //
 0164                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
 0165                            new EncryptedTokenDecryptionFailedException(
 0166                            SR.Format(SR.ID4036, XmlUtil.SerializeSecurityKeyIdentifier(encryptedData.KeyIdentifier, bas
 167                }
 168                else
 169                {
 0170                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
 0171                            new EncryptedTokenDecryptionFailedException(SR.Format(SR.ID4036, encryptedData.KeyIdentifier
 172                }
 173            }
 174
 175            //
 176            // Need a symmetric key
 177            //
 0178            if (!(decryptionKey is SymmetricSecurityKey symmetricKey))
 179            {
 0180                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
 0181                    new SecurityTokenException(SR.Format(SR.ID4023)));
 182            }
 183
 184            //
 185            // Do the actual decryption
 186            //
 187            byte[] plainText;
 188
 0189            using (SymmetricAlgorithm decrypter = symmetricKey.GetSymmetricAlgorithm(encryptedData.Algorithm))
 190            {
 0191                plainText = encryptedData.Decrypt(decrypter);
 0192            }
 193
 194            DebugEncryptedTokenClearText(plainText, Encoding.UTF8);
 195
 196            //
 197            // Read and return the plaintext token
 198            //
 0199            using (XmlReader innerTokenReader = XmlDictionaryReader.CreateTextReader(plainText, XmlDictionaryReaderQuota
 200            {
 0201                if (ContainingCollection != null && ContainingCollection.CanReadToken(innerTokenReader))
 202                {
 0203                    return ContainingCollection.ReadToken(innerTokenReader);
 204                }
 0205                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInvalidOperation(SR.Format(SR.ID4014, innerTokenRead
 206            }
 0207        }
 208
 209        /// <summary>
 210        /// Reads an EncryptedKeyIdentifierClause from a XML stream.
 211        /// </summary>
 212        /// <param name=nameof(reader)>An XML reader positioned at an EncryptedKey element as defined in 'http://www.w3.
 213        /// <returns>SecurityKeyIdentifierClause instance of type EncryptedKeyIdentifierClause.</returns>
 214        /// <exception cref="ArgumentNullException">The <paramref name=nameof(reader)/> is null.</exception>
 215        /// <exception cref="InvalidOperationException">If the <paramref name=nameof(reader)/> is not positioned at an E
 216        public override SecurityKeyIdentifierClause ReadKeyIdentifierClause(XmlReader reader)
 217        {
 0218            if (reader == null)
 219            {
 0220                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(reader));
 221            }
 222
 223            // <EncryptedKey>
 0224            if (reader.IsStartElement(XmlEncryptionConstants.Elements.EncryptedKey, XmlEncryptionConstants.Namespace))
 225            {
 0226                EncryptedKeyElement encryptedKey = new EncryptedKeyElement(KeyInfoSerializer);
 0227                encryptedKey.ReadXml(XmlDictionaryReader.CreateDictionaryReader(reader));
 0228                return new EncryptedKeyIdentifierClause(encryptedKey.CipherData.CipherValue, encryptedKey.Algorithm, enc
 229            }
 230
 0231            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.ID3275,
 232        }
 233
 234        [Conditional("DEBUG")]
 235        private static void DebugEncryptedTokenClearText(byte[] bytes, Encoding encoding)
 236        {
 0237            string text = encoding.GetString(bytes);
 238            Debug.WriteLine(text.Substring(0, 40));
 0239        }
 240
 241        /// <summary>
 242        /// Gets the System.Type of the token that this SecurityTokenHandler handles.
 243        /// Returns typeof <see cref="EncryptedSecurityToken"/> by default.
 244        /// </summary>
 14245        public override Type TokenType => typeof(EncryptedSecurityToken);
 246
 247        /// <summary>
 248        /// By default returns an array with a single null string as there isn't any specific TokenType identifier that 
 249        /// associated with a <see cref="EncryptedSecurityToken"/>.
 250        /// </summary>
 8251        public override string[] GetTokenTypeIdentifiers() => s_tokenTypeIdentifiers;
 252
 253        /// <summary>
 254        /// Writes a <see cref="EncryptedSecurityToken"/> using the xmlWriter.
 255        /// </summary>
 256        /// <param name="writer">The XmlWriter to which the encrypted token is written.</param>
 257        /// <param name=nameof(token)>The <see cref="SecurityToken"/> which must be an instance of <see cref="EncryptedS
 258        /// <exception cref="ArgumentNullException">The input prameter 'writer' is null.</exception>
 259        /// <exception cref="ArgumentNullException">The input prameter 'token' is null.</exception>
 260        /// <exception cref="ArgumentException">The <see cref="SecurityToken"/> is not an instance of <see cref="Encrypt
 261        /// <exception cref="InvalidOperationException">The property 'Configuration' is null. This property is required 
 262        /// <exception cref="InvalidOperationException">The ContaingCollection was unable to find a <see cref="SecurityT
 263        /// the <see cref="SecurityToken"/> returned by 'EncryptedSecurityToken.Token'.</exception>
 264        /// <exception cref="SecurityTokenException">The property 'EncryptinCredentials.SecurityKey is not a <see cref="
 265        public override void WriteToken(XmlWriter writer, SecurityToken token)
 266        {
 0267            if (null == writer)
 268            {
 0269                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(writer));
 270            }
 271
 0272            if (null == token)
 273            {
 0274                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(token));
 275            }
 276
 0277            if (!(token is EncryptedSecurityToken encryptedToken))
 278            {
 0279                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(nameof(token), SR.Format(SR.ID4024));
 280            }
 281
 0282            if (ContainingCollection == null)
 283            {
 0284                throw DiagnosticUtility.ExceptionUtility.ThrowHelperInvalidOperation(SR.Format(SR.ID4279));
 285            }
 286
 287            //
 288            // This implementation simply wraps the token in xenc:EncryptedData
 289            //
 0290            EncryptedDataElement encryptedData = new EncryptedDataElement(KeyInfoSerializer);
 0291            using (MemoryStream plaintextStream = new MemoryStream())
 292            {
 293                //
 294                // Buffer the plaintext
 295                //
 0296                using (XmlDictionaryWriter plaintextWriter = XmlDictionaryWriter.CreateTextWriter(plaintextStream, Encod
 297                {
 0298                    SecurityTokenHandler securityTokenHandler = ContainingCollection[encryptedToken.Token.GetType()];
 0299                    if (securityTokenHandler != null)
 300                    {
 0301                        securityTokenHandler.WriteToken(plaintextWriter, encryptedToken.Token);
 302                    }
 303                    else
 304                    {
 0305                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperInvalidOperation(SR.Format(SR.ID4224, encryp
 306                    }
 307                }
 308
 309                //
 310                // Set up the EncryptedData element
 311                //
 0312                EncryptingCredentials encryptingCredentials = encryptedToken.EncryptingCredentials;
 0313                encryptedData.Type = XmlEncryptionConstants.EncryptedDataTypes.Element;
 0314                encryptedData.KeyIdentifier = encryptingCredentials.SecurityKeyIdentifier;
 0315                encryptedData.Algorithm = encryptingCredentials.Algorithm;
 316
 317                //
 318                // Get the encryption key, which must be symmetric
 319                //
 0320                if (!(encryptingCredentials.SecurityKey is SymmetricSecurityKey encryptingKey))
 321                {
 0322                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.Format(SR.ID
 323                }
 324
 325                //
 326                // Do the actual encryption
 327                //
 0328                using (SymmetricAlgorithm symmetricAlgorithm = encryptingKey.GetSymmetricAlgorithm(encryptingCredentials
 329                {
 0330                    byte[] plainTextBytes = plaintextStream.GetBuffer();
 331                    DebugEncryptedTokenClearText(plainTextBytes, Encoding.UTF8);
 0332                    encryptedData.Encrypt(symmetricAlgorithm, plainTextBytes, 0, (int)plaintextStream.Length);
 0333                }
 334            }
 335
 336            //
 337            // Write the EncryptedData element
 338            //
 0339            encryptedData.WriteXml(writer, KeyInfoSerializer);
 0340        }
 341    }
 342}