< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.IdentityModel.Tokens.SamlSerializer
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/IdentityModel/Tokens/SamlSerializer.cs
Line coverage
56%
Covered lines: 86
Uncovered lines: 65
Coverable lines: 151
Total lines: 347
Line coverage: 56.9%
Branch coverage
36%
Covered branches: 38
Total branches: 104
Branch coverage: 36.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor()100%11100%
ReadToken(...)42.3%262676.59%
TryCreateMicrosoftIdentityVerificationKey(...)7.14%141413.33%
LoadAssertion(...)50%101072.22%
ResolveSecurityKey(...)0%14140%
ResolveSecurityKey(...)40%101055.55%
ResolveSecurityToken(...)60%101060%
CreateSecurityKeyIdentifier(...)55.55%181850%
CreateStrSecurityKeyIdentifier(...)50%2290.9%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/IdentityModel/Tokens/SamlSerializer.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.Collections.Generic;
 6using System.Collections.ObjectModel;
 7using System.Security.Cryptography.X509Certificates;
 8using System.Text;
 9using System.Xml;
 10using CoreWCF.IdentityModel.Selectors;
 11using Microsoft.IdentityModel.Tokens.Saml;
 12using MSSAmlSerializer = Microsoft.IdentityModel.Tokens.Saml.SamlSerializer;
 13
 14namespace CoreWCF.IdentityModel.Tokens
 15{
 16    public class SamlSerializer
 17    {
 18        private readonly MSSAmlSerializer _mSSamlSerializer;
 19
 13520        public SamlSerializer()
 21        {
 13522            _mSSamlSerializer = new MSSAmlSerializer();
 13523            _mSSamlSerializer.DSigSerializer = new Saml.DSigSerializerExtended();
 13524        }
 25
 26        public virtual SamlSecurityToken ReadToken(XmlDictionaryReader reader, SecurityTokenSerializer keyInfoSerializer
 27        {
 328            if (reader == null)
 29            {
 030                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(reader));
 31            }
 32
 333            if (keyInfoSerializer == null)
 34            {
 035                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(keyInfoSerializer));
 36            }
 37
 338            SecurityToken? signingToken = null;
 339            SecurityKey? verificationKey = null;
 340            var assertion = LoadAssertion(reader, keyInfoSerializer, outOfBandTokenResolver, out signingToken, out verif
 41
 342            if (assertion == null)
 43            {
 044                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.Format(SR.SAMLUn
 45            }
 46
 347            var imSamlSecurityToken = new Microsoft.IdentityModel.Tokens.Saml.SamlSecurityToken(assertion);
 348            var samlSecurityToken = new SamlSecurityToken(imSamlSecurityToken, new ReadOnlyCollection<SecurityKey?>(new 
 349            samlSecurityToken.SigningToken = signingToken;
 350            SecurityKeyIdentifier securityKeyIdentifier = CreateSecurityKeyIdentifier(assertion.Signature.KeyInfo, keyIn
 51
 1452            foreach (var stmt in assertion.Statements)
 53            {
 454                SamlSubjectStatement samlSubject = (SamlSubjectStatement)stmt;
 455                SecurityKeyIdentifier keyIdentifier = null;
 456                SecurityToken securityToken = null;
 457                if (samlSubject.Subject.KeyInfo != null)
 58                {
 159                    keyIdentifier = CreateSecurityKeyIdentifier(samlSubject.Subject.KeyInfo, keyInfoSerializer);
 160                    securityToken = ResolveSecurityToken(securityKeyIdentifier, outOfBandTokenResolver);
 61                }
 462                var internalSamlSubjectStatement = new InternalSamlSubjectStatement(samlSubject, keyIdentifier, security
 463                samlSecurityToken.SamlStatements.Add(internalSamlSubjectStatement);
 64            }
 65
 66            //do a final validation on signature.
 367            if (signingToken is X509SecurityToken x509signingToken)
 68            {
 169                Microsoft.IdentityModel.Tokens.X509SecurityKey? imX509SecurityKey = null;
 170                var cryptoProviderFactory = new CoreWCF.Security.Sha1CryptoProviderFactory();
 71                try
 72                {
 173                    imX509SecurityKey = new Microsoft.IdentityModel.Tokens.X509SecurityKey(x509signingToken.Certificate)
 174                    imX509SecurityKey.CryptoProviderFactory = cryptoProviderFactory;
 175                    assertion.Signature.Verify(imX509SecurityKey, cryptoProviderFactory);
 176                }
 077                catch (Microsoft.IdentityModel.Xml.XmlValidationException xve)
 78                {
 079                    if (xve.Message.Contains("SignatureMethod is not supported"))
 80                    {
 081                        if (imX509SecurityKey?.PublicKey is null)
 82                        {
 083                            throw new SecurityTokenException(SR.Format(SR.PublicKeyNotFoundInX509SecurityKey, assertion.
 84                        }
 85
 086                        throw new SecurityTokenException(SR.Format(SR.SignatureMethodNotSupported, assertion.Signature.S
 87                    }
 88
 089                    throw;
 90                }
 91            }
 92            else
 93            {
 294                Microsoft.IdentityModel.Tokens.SecurityKey msVerificationKey = TryCreateMicrosoftIdentityVerificationKey
 295                if (msVerificationKey == null)
 96                {
 097                    throw new SecurityTokenException(SR.Format(SR.SamlSignatureVerificationKeyNotSupported, verification
 98                }
 99
 2100                var cryptoProviderFactory = new CoreWCF.Security.Sha1CryptoProviderFactory();
 2101                msVerificationKey.CryptoProviderFactory = cryptoProviderFactory;
 102                try
 103                {
 2104                    assertion.Signature.Verify(msVerificationKey, cryptoProviderFactory);
 1105                }
 1106                catch (Microsoft.IdentityModel.Xml.XmlValidationException xve)
 107                {
 1108                    if (xve.Message.Contains("SignatureMethod is not supported"))
 109                    {
 0110                        throw new SecurityTokenException(SR.Format(SR.SignatureMethodNotSupported, assertion.Signature.S
 111                    }
 112
 1113                    throw;
 114                }
 115            }
 116
 2117            return samlSecurityToken;
 118        }
 119
 120        private static Microsoft.IdentityModel.Tokens.SecurityKey TryCreateMicrosoftIdentityVerificationKey(SecurityKey 
 121        {
 2122            if (verificationKey is SymmetricSecurityKey symmetricKey)
 123            {
 2124                return new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(symmetricKey.GetSymmetricKey());
 125            }
 126
 0127            if (verificationKey is RsaSecurityKey rsaKey)
 128            {
 0129                System.Security.Cryptography.AsymmetricAlgorithm asym =
 0130                    rsaKey.GetAsymmetricAlgorithm(SecurityAlgorithms.RsaSha256Signature, false)
 0131                    ?? rsaKey.GetAsymmetricAlgorithm(SecurityAlgorithms.RsaSha1Signature, false);
 132
 0133                if (asym is System.Security.Cryptography.RSA rsa)
 134                {
 0135                    return new Microsoft.IdentityModel.Tokens.RsaSecurityKey(rsa);
 136                }
 137            }
 138
 0139            if (verificationKey is X509AsymmetricSecurityKey x509AsymKey)
 140            {
 0141                System.Security.Cryptography.AsymmetricAlgorithm asym =
 0142                    x509AsymKey.GetAsymmetricAlgorithm(SecurityAlgorithms.RsaSha256Signature, false)
 0143                    ?? x509AsymKey.GetAsymmetricAlgorithm(SecurityAlgorithms.RsaSha1Signature, false);
 144
 0145                if (asym is System.Security.Cryptography.RSA rsa)
 146                {
 0147                    return new Microsoft.IdentityModel.Tokens.RsaSecurityKey(rsa);
 148                }
 149            }
 150
 0151            return null;
 152        }
 153
 154        private SamlAssertion LoadAssertion(XmlDictionaryReader reader, SecurityTokenSerializer keyInfoSerializer, Secur
 155        {
 3156            if (reader == null)
 0157                throw new ArgumentNullException(nameof(reader));
 158
 3159            SamlAssertion assertion = _mSSamlSerializer.ReadAssertion(reader);
 3160            SecurityKeyIdentifier securityKeyIdentifier = CreateSecurityKeyIdentifier(assertion.Signature.KeyInfo, keyIn
 3161            CoreWCF.IdentityModel.SecurityKeyIdentifierClause? securityKeyIdentifierClause = null;
 3162            verificationKey = null;
 3163            signingToken = null;
 3164            if (securityKeyIdentifier.Count < 2 /*|| LocalAppContextSwitches.ProcessMultipleSecurityKeyIdentifierClauses
 165            {
 3166                verificationKey = SamlSerializer.ResolveSecurityKey(securityKeyIdentifier, outOfBandTokenResolver);
 167            }
 168            else
 169            {
 0170                verificationKey = ResolveSecurityKey(securityKeyIdentifier, outOfBandTokenResolver, out securityKeyIdent
 171            }
 172
 3173            if (verificationKey == null)
 174            {
 0175                throw new SecurityTokenException(SR.Format(SR.SAMLUnableToResolveSignatureKey, assertion.Issuer));
 176            }
 177
 3178            if (securityKeyIdentifier.Count < 2 /*|| LocalAppContextSwitches.ProcessMultipleSecurityKeyIdentifierClauses
 179            {
 3180                signingToken = SamlSerializer.ResolveSecurityToken(securityKeyIdentifier, outOfBandTokenResolver);
 181            }
 182            else
 183            {
 0184                signingToken = SamlSerializer.ResolveSecurityToken(new SecurityKeyIdentifier(securityKeyIdentifierClause
 185            }
 186
 3187            if (signingToken == null)
 188            {
 0189                throw new SecurityTokenException(SR.SamlSigningTokenNotFound);
 190            }
 191
 3192            return assertion;
 193        }
 194
 195        private static SecurityKey ResolveSecurityKey(SecurityKeyIdentifier ski, SecurityTokenResolver tokenResolver, ou
 196        {
 0197            if (ski == null)
 0198                throw new ArgumentNullException(nameof(ski));
 199
 0200            clause = null;
 201
 0202            if (tokenResolver != null)
 203            {
 0204                for (int i = 0; i < ski.Count; ++i)
 205                {
 0206                    SecurityKey? key = null;
 0207                    if (tokenResolver.TryResolveSecurityKey(ski[i], out key))
 208                    {
 0209                        clause = ski[i];
 0210                        return key;
 211                    }
 212                }
 213            }
 214
 0215            if (ski.CanCreateKey)
 216            {
 0217                foreach (var skiClause in ski)
 218                {
 0219                    if (skiClause.CanCreateKey)
 220                    {
 0221                        clause = skiClause;
 0222                        return clause.CreateKey();
 223                    }
 224                }
 225
 0226                throw new InvalidOperationException(SR.KeyIdentifierCannotCreateKey);
 227            }
 228
 0229            return null;
 0230        }
 231
 232
 233        internal static SecurityKey ResolveSecurityKey(SecurityKeyIdentifier ski, SecurityTokenResolver tokenResolver)
 234        {
 3235            if (ski == null)
 0236                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(ski));
 237
 3238            if (tokenResolver != null)
 239            {
 6240                for (int i = 0; i < ski.Count; ++i)
 241                {
 3242                    if (tokenResolver.TryResolveSecurityKey(ski[i], out SecurityKey key))
 3243                        return key;
 244                }
 245            }
 246
 0247            if (ski.CanCreateKey)
 0248                return ski.CreateKey();
 249
 0250            return null;
 251        }
 252
 253        internal static SecurityToken ResolveSecurityToken(SecurityKeyIdentifier ski, SecurityTokenResolver tokenResolve
 254        {
 4255            SecurityToken token = null;
 256
 4257            if (tokenResolver != null)
 258            {
 4259                tokenResolver.TryResolveToken(ski, out token);
 260            }
 261
 4262            if (token == null)
 263            {
 264                // Check if this is a RSA key.
 0265                if (ski.TryFind(out RsaKeyIdentifierClause rsaClause))
 0266                    token = new RsaSecurityToken(rsaClause.Rsa);
 267            }
 268
 4269            if (token == null)
 270            {
 271                // Check if this is a X509RawDataKeyIdentifier Clause.
 0272                if (ski.TryFind(out X509RawDataKeyIdentifierClause rawDataKeyIdentifierClause))
 0273                    token = new X509SecurityToken(new X509Certificate2(rawDataKeyIdentifierClause.GetX509RawData()));
 274            }
 275
 4276            return token;
 277        }
 278
 279        internal static SecurityKeyIdentifier CreateSecurityKeyIdentifier(Microsoft.IdentityModel.Xml.KeyInfo keyInfo, S
 280        {
 7281            var ski = new SecurityKeyIdentifier();
 7282            if (keyInfo == null)
 283            {
 0284                return ski;
 285            }
 286
 7287            if (keyInfo.RSAKeyValue != null)
 288            {
 0289                throw new InvalidOperationException(SR.SamlRSANotSupported);
 290            }
 291
 14292            foreach (var objdata in keyInfo.X509Data)
 293            {
 0294                foreach (string certificateStr in objdata.Certificates)
 295                {
 0296                    byte[] data = Convert.FromBase64String(certificateStr);
 0297                    ski.Add(new X509RawDataKeyIdentifierClause(data));
 298                }
 299
 0300                if (objdata.IssuerSerial != null)
 301                {
 0302                    ski.Add(new X509IssuerSerialKeyIdentifierClause(objdata.IssuerSerial.IssuerName, objdata.IssuerSeria
 303                }
 304
 0305                if (!string.IsNullOrWhiteSpace(objdata.SKI))
 306                {
 0307                    byte[] data = Convert.FromBase64String(objdata.SKI);
 0308                    ski.Add(new X509SubjectKeyIdentifierClause(data));
 309                }
 310            }
 311
 7312            if (keyInfo is Saml.KeyInfo coreWcfKeyInfo)
 313            {
 7314                if (coreWcfKeyInfo.SecurityTokenReference != null)
 315                {
 6316                    var strIdentifierClause = CreateStrSecurityKeyIdentifier(coreWcfKeyInfo.SecurityTokenReference, keyI
 6317                    if (strIdentifierClause != null)
 318                    {
 6319                        ski.Add(strIdentifierClause);
 320                    }
 321                }
 322            }
 323
 7324            return ski;
 325        }
 326
 327        private static SecurityKeyIdentifierClause? CreateStrSecurityKeyIdentifier(Saml.SecurityTokenReference securityT
 328        {
 6329            var ski = securityTokenReference.SecurityKeyIdentifier;
 6330            var strString = $"""
 6331                <o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-se
 6332                  <o:KeyIdentifier ValueType="{ski.ValueType}" EncodingType="{ski.EncodingType}">{ski.Value}</o:KeyIdent
 6333                </o:SecurityTokenReference>
 6334                """;
 335
 6336            var dictReader = XmlDictionaryReader.CreateTextReader(Encoding.UTF8.GetBytes(strString), XmlDictionaryReader
 6337            dictReader.MoveToContent();
 6338            if (!keyInfoSerializer.CanReadKeyIdentifierClause(dictReader))
 339            {
 0340                return null;
 341            }
 342
 6343            return keyInfoSerializer.ReadKeyIdentifierClause(dictReader);
 344        }
 345
 346    }
 347}