From 57deb67eaf2388e1f056abab6c652fc79aee893c Mon Sep 17 00:00:00 2001 From: Maria Furman Date: Tue, 15 Jan 2019 11:43:22 -0800 Subject: [PATCH] Updated VerifyResourceUsage.pl to check log messages across all directories --- .../LogMessages.cs | 58 ++-- src/VerifyResourceUsage.pl | 264 +++++++----------- 2 files changed, 134 insertions(+), 188 deletions(-) diff --git a/src/Microsoft.IdentityModel.Tokens/LogMessages.cs b/src/Microsoft.IdentityModel.Tokens/LogMessages.cs index 2e1900e965..8d1bcfacae 100644 --- a/src/Microsoft.IdentityModel.Tokens/LogMessages.cs +++ b/src/Microsoft.IdentityModel.Tokens/LogMessages.cs @@ -37,7 +37,7 @@ internal static class LogMessages { #pragma warning disable 1591 // general - public const string IDX10000 = "IDX10000: The parameter '{0}' cannot be a 'null' or an empty object."; + // public const string IDX10000 = "IDX10000:"; // properties, configuration public const string IDX10101 = "IDX10101: MaximumTokenSizeInBytes must be greater than zero. value: '{0}'"; @@ -78,7 +78,7 @@ internal static class LogMessages public const string IDX10244 = "IDX10244: Issuer is null or empty. Using runtime default for creating claims '{0}'."; public const string IDX10245 = "IDX10245: Creating claims identity from the validated token: '{0}'."; public const string IDX10246 = "IDX10246: ValidateTokenReplay property on ValidationParameters is set to false. Exiting without validating the token replay."; - public const string IDX10247 = "IDX10247: The current issuer value in ValidateIssuers property on ValidationParameters is null or empty, skipping it for issuer validation."; + // public const string IDX10247 = "IDX10247:"; public const string IDX10248 = "IDX10248: X509SecurityKey validation failed. The associated certificate is not yet valid. ValidFrom (UTC): '{0}', Current time (UTC): '{1}'."; public const string IDX10249 = "IDX10249: X509SecurityKey validation failed. The associated certificate has expired. ValidTo (UTC): '{0}', Current time (UTC): '{1}'."; public const string IDX10250 = "IDX10250: The associated certificate is valid. ValidFrom (UTC): '{0}', Current time (UTC): '{1}'."; @@ -98,27 +98,27 @@ internal static class LogMessages public const string IDX10504 = "IDX10504: Unable to validate signature, token does not have a signature: '{0}'."; public const string IDX10505 = "IDX10505: Signature validation failed. The user defined 'Delegate' specified on TokenValidationParameters returned null when validating token: '{0}'."; public const string IDX10506 = "IDX10506: Signature validation failed. The user defined 'Delegate' specified on TokenValidationParameters did not return a '{0}', but returned a '{1}' when validating token: '{2}'."; - public const string IDX10507 = "IDX10507: Signature validation failed. ValidateSignature returned null when validating token: '{0}'."; + // public const string IDX10507 = "IDX10507:"; public const string IDX10508 = "IDX10508: Signature validation failed. Signature is improperly formatted."; public const string IDX10509 = "IDX10509: Signature validation failed. The user defined 'Delegate' specified in TokenValidationParameters did not return a '{0}', but returned a '{1}' when reading token: '{2}'."; public const string IDX10510 = "IDX10510: Signature validation failed. The user defined 'Delegate' specified in TokenValidationParameters returned null when reading token: '{0}'."; public const string IDX10511 = "IDX10511: Signature validation failed. Keys tried: '{0}'. \nkid: '{1}'. \nExceptions caught:\n '{2}'.\ntoken: '{3}'."; // encryption / decryption - public const string IDX10600 = "IDX10600: Decryption failed. There are no security keys for decryption."; - public const string IDX10601 = "IDX10601: Decryption failed. Unable to match 'kid': '{0}', \ntoken: '{1}'."; + // public const string IDX10600 = "IDX10600:"; + // public const string IDX10601 = "IDX10601:"; public const string IDX10603 = "IDX10603: Decryption failed. Keys tried: '{0}'.\nExceptions caught:\n '{1}'.\ntoken: '{2}'"; - public const string IDX10604 = "IDX10604: Decryption failed. Exception: '{0}'."; - public const string IDX10605 = "IDX10605: Decryption failed. Only 'dir' is currently supported. JWE alg is: '{0}'."; - public const string IDX10606 = "IDX10606: Decryption failed. To decrypt a JWE there must be 5 parts. 'tokenParts' is of length: '{0}'."; + // public const string IDX10604 = "IDX10604:"; + // public const string IDX10605 = "IDX10605:"; + // public const string IDX10606 = "IDX10606:"; public const string IDX10607 = "IDX10607: Decryption skipping key: '{0}', both validationParameters.CryptoProviderFactory and key.CryptoProviderFactory are null."; - public const string IDX10608 = "IDX10608: Decryption skipping key: '{0}', it is not a '{1}'."; + // public const string IDX10608 = "IDX10608:"; public const string IDX10609 = "IDX10609: Decryption failed. No Keys tried: token: '{0}'."; public const string IDX10610 = "IDX10610: Decryption failed. Could not create decryption provider. Key: '{0}', Algorithm: '{1}'."; public const string IDX10611 = "IDX10611: Decryption failed. Encryption is not supported for: Algorithm: '{0}', SecurityKey: '{1}'."; public const string IDX10612 = "IDX10612: Decryption failed. Header.Enc is null or empty, it must be specified."; - //public const string IDX10613 = "IDX10613:" - public const string IDX10614 = "IDX10614: Decryption failed. JwtHeader.Base64UrlDeserialize(tokenParts[0]): '{0}'. Inner exception: '{1}'."; + // public const string IDX10613 = "IDX10613:"; + // public const string IDX10614 = "IDX10614:"; public const string IDX10615 = "IDX10615: Encryption failed. No support for: Algorithm: '{0}', SecurityKey: '{1}'."; public const string IDX10616 = "IDX10616: Encryption failed. EncryptionProvider failed for: Algorithm: '{0}', SecurityKey: '{1}'. See inner exception."; public const string IDX10617 = "IDX10617: Encryption failed. Keywrap is only supported for: '{0}', '{1}' and '{2}'. The content encryption specified is: '{3}'."; @@ -129,38 +129,38 @@ internal static class LogMessages // Crypto Errors public const string IDX10621 = "IDX10621: '{0}' supports: '{1}' of types: '{2}' or '{3}'. SecurityKey received was of type '{4}'."; - public const string IDX10622 = "IDX10622: The algorithm: '{0}' requires the SecurityKey.KeySize to be greater than '{1}' bits. KeySize reported: '{2}'."; - public const string IDX10623 = "IDX10623: Cannot sign data because the KeyedHashAlgorithm is null."; - public const string IDX10624 = "IDX10624: Cannot verify data because the KeyedHashAlgorithm is null."; - public const string IDX10627 = "IDX10627: Cannot set the MinimumAsymmetricKeySizeInBitsForVerifying to less than '{0}'."; + // public const string IDX10622 = "IDX10622:"; + // public const string IDX10623 = "IDX10623:"; + // public const string IDX10624 = "IDX10624:"; + // public const string IDX10627 = "IDX10627:"; public const string IDX10628 = "IDX10628: Cannot set the MinimumSymmetricKeySizeInBits to less than '{0}'."; public const string IDX10630 = "IDX10630: The '{0}' for signing cannot be smaller than '{1}' bits. KeySize: '{2}'."; public const string IDX10631 = "IDX10631: The '{0}' for verifying cannot be smaller than '{1}' bits. KeySize: '{2}'."; public const string IDX10634 = "IDX10634: Unable to create the SignatureProvider.\nAlgorithm: '{0}', SecurityKey: '{1}'\n is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms"; - public const string IDX10635 = "IDX10635: Unable to create signature. '{0}' returned a null '{1}'. SecurityKey: '{2}', Algorithm: '{3}'"; + // public const string IDX10635 = "IDX10635:"; public const string IDX10636 = "IDX10636: CryptoProviderFactory.CreateForVerifying returned null for key: '{0}', signatureAlgorithm: '{1}'."; public const string IDX10638 = "IDX10638: Cannot create the SignatureProvider, 'key.HasPrivateKey' is false, cannot create signatures. Key: {0}."; public const string IDX10640 = "IDX10640: Algorithm is not supported: '{0}'."; - public const string IDX10641 = "IDX10641: Key is not supported: '{0}'."; + // public const string IDX10641 = "IDX10641:"; public const string IDX10642 = "IDX10642: Creating signature using the input: '{0}'."; public const string IDX10643 = "IDX10643: Comparing the signature created over the input with the token signature: '{0}'."; - public const string IDX10644 = "IDX10644: UnwrapKey failed. Algorithm: '{0}'."; + // public const string IDX10644 = "IDX10644:"; public const string IDX10645 = "IDX10645: Elliptical Curve not supported for curveId: '{0}'"; public const string IDX10646 = "IDX10646: A CustomCryptoProvider was set and returned 'true' for IsSupportedAlgorithm(Algorithm: '{0}', Key: '{1}'), but Create.(algorithm, args) as '{2}' == NULL."; public const string IDX10647 = "IDX10647: A CustomCryptoProvider was set and returned 'true' for IsSupportedAlgorithm(Algorithm: '{0}'), but Create.(algorithm, args) as '{1}' == NULL."; - public const string IDX10648 = "IDX10648: The SecurityKey provided for AuthenticatedEncryption must be a SymmetricSecurityKey. Type is: '{0}'."; + // public const string IDX10648 = "IDX10648:"; public const string IDX10649 = "IDX10649: Failed to create a SymmetricSignatureProvider for the algorithm '{0}'."; public const string IDX10650 = "IDX10650: Failed to verify ciphertext with aad '{0}'; iv '{1}'; and authenticationTag '{2}'."; - public const string IDX10651 = "IDX10651: The key length for the algorithm '{0]' cannot be less than '{1}'."; + // public const string IDX10651 = "IDX10651:"; public const string IDX10652 = "IDX10652: The algorithm '{0}' is not supported."; public const string IDX10653 = "IDX10653: The encryption algorithm '{0}' requires a key size of at least '{1}' bits. Key '{2}', is of size: '{3}'."; public const string IDX10654 = "IDX10654: Decryption failed. Cryptographic operation exception: '{0}'."; public const string IDX10655 = "IDX10655: 'length' must be greater than 1: '{0}'"; - public const string IDX10656 = "IDX10656: 'length' cannot be greater than signature.Length. length: '{0}', signature.Length: '{1}'."; + // public const string IDX10656 = "IDX10656:"; public const string IDX10657 = "IDX10657: The SecurityKey provided for the symmetric key wrap algorithm cannot be converted to byte array. Type is: '{0}'."; public const string IDX10658 = "IDX10658: WrapKey failed, exception from cryptographic operation: '{0}'"; public const string IDX10659 = "IDX10659: UnwrapKey failed, exception from cryptographic operation: '{0}'"; - public const string IDX10660 = "IDX10660: The Key: '{0}' and algorithm: '{1}' pair are not supported."; + // public const string IDX10660 = "IDX10660:"; public const string IDX10661 = "IDX10661: Unable to create the KeyWrapProvider.\nKeyWrapAlgorithm: '{0}', SecurityKey: '{1}'\n is not supported."; public const string IDX10662 = "IDX10662: The KeyWrap algorithm '{0}' requires a key size of '{1}' bits. Key '{2}', is of size:'{3}'."; public const string IDX10663 = "IDX10663: Failed to create symmetric algorithm with SecurityKey: '{0}', KeyWrapAlgorithm: '{1}'."; @@ -170,18 +170,18 @@ internal static class LogMessages public const string IDX10667 = "IDX10667: Unable to obtain required byte array for KeyHashAlgorithm from SecurityKey: '{0}'."; public const string IDX10668 = "IDX10668: Unable to create '{0}', algorithm '{1}'; key: '{2}' is not supported."; public const string IDX10669 = "IDX10669: Failed to create symmetric algorithm."; - public const string IDX10670 = "IDX10670: The lengths of the two byte arrays do not match. The first one has: '{0}' bytes, the second one has: '{1}' bytes."; - public const string IDX10671 = "IDX10671: The ECDsa Key: '{0}' must be '{1}' bits. KeySize: '{2}'."; - public const string IDX10672 = "IDX10672: GetKeyedHashAlgorithm returned null, key: {0}, algorithm {1}."; - public const string IDX10673 = "IDX10673: CryptoProviderFactory.GetHashAlgorithm returned null, factory: {0}, algorithm: {1}."; + // public const string IDX10670 = "IDX10670:"; + // public const string IDX10671 = "IDX10671:"; + // public const string IDX10672 = "IDX10672:"; + // public const string IDX10673 = "IDX10673:"; public const string IDX10674 = "IDX10674: JsonWebKeyConverter does not support SecurityKey of type: {0}"; public const string IDX10675 = "IDX10675: The byte count of '{0}' must be less than or equal to '{1}', but was {2}."; - //public const string IDX10676 = "IDX10676:" + // public const string IDX10676 = "IDX10676:"; public const string IDX10677 = "IDX10677: GetKeyedHashAlgorithm threw, key: {0}, algorithm {1}."; - public const string IDX10678 = "IDX10678: Unable to Sign, provider is not available, Algorithm, Key: '{0}', '{1}'."; + // public const string IDX10678 = "IDX10678:"; public const string IDX10679 = "IDX10679: Failed to decompress using algorithm '{0}'."; public const string IDX10680 = "IDX10680: Failed to compress using algorithm '{0}'."; - public const string IDX10681 = "IDX10681: Unable to create the CompressionProvider.\nAlgorithm: '{0}' is not supported."; + // public const string IDX10681 = "IDX10681:"; public const string IDX10682 = "IDX10682: Compression algorithm '{0}' is not supported."; // public const string IDX10683 = "IDX10683:"; public const string IDX10684 = "IDX10684: Unable to convert the JsonWebKey to an AsymmetricSecurityKey. Algorithm: '{0}', Key: '{1}'."; diff --git a/src/VerifyResourceUsage.pl b/src/VerifyResourceUsage.pl index 8edb9ac922..1281a219d6 100644 --- a/src/VerifyResourceUsage.pl +++ b/src/VerifyResourceUsage.pl @@ -1,13 +1,13 @@ -#!/usr/bin/perl ###################################################################### -# verify_resource_usage.pl +# VerifyResourceUsage.pl ###################################################################### -# run like this: +# Run like this: # perl VerifyResourceUsage.pl -# to discover +# To discover # 1) what LogMessages.cs strings are unused # 2) whether any of the string IDs and string value prefixes don't match # 3) whether any LogMessages.cs files contain duplicate IDs +# 4) whether any commented out IDs have been accidentally reused use strict; use strict 'subs'; @@ -18,15 +18,12 @@ use File::Find; use File::Basename; -# TODO the script doesn't know about comments and #if, so it can have false-positives on commented-out code... - -my $PERF_DEBUG = (1==0); # print debug info to screen, so a human watching output in real time can see where time spent +my $PERF_DEBUG = (1==0); # print debug info to screen my $ERRORS_ONLY_MODE = (1==0); # only print serious errors -my $THERE_ARE_ERRORS = (1==0); -# prefix strings so build won't filter messages -my $ERROR = "verify_resource_usage.pl(): error"; -my $WARN = "verify_resource_usage.pl(): warning"; -my $TELL = "BUILDMSG:"; + +# prefix strings +my $ERROR = "VerifyResourceUsage.pl: error"; +my $WARN = "VerifyResourceUsage.pl: warning"; my $EXITCODE = 0; my $CROP_FILE_PATH_AT = "src"; @@ -39,7 +36,6 @@ ($) if ($ERRORS_ONLY_MODE) { print "$ERROR $s"; - $THERE_ARE_ERRORS = 1; } else { @@ -95,7 +91,7 @@ ($) my $FORMAT_STR_ARG = qr/ (?) { next if /^;/; # lines starting with ';' are comments next if /^#/; # lines starting with '#' are comments - next if /\/\//; # lines starting with '//' are comments - next if not /internal const string (\w*?)\s*=(.*)/; - my $id = $1; # identifier is everything up to '=' - my $value = $2; # rest is actual resource string value - - my $numArgs = CountArgs($id, $value); - VerifyNumBraces($id, $value); - $ids{$id} = [0,$numArgs,$value]; - # go through each directory that we've processed so far - foreach my $directory2 (keys(%dirhash)) - { - # checking for duplicate ids in the same directory is unnecessary - if (not $directory eq $directory2) { - if (grep {$_ eq $id} @{$dirhash{$directory2}}) - { - PrintError("\nSame id ($id) is reused in the LogMessages.cs file of both: \n $directory \n and \n $directory2 \n \n"); - } - } - } - push @{$dirhash{$directory}}, $id; - } + next if not /(\/\/)?\s*(internal|public) const string (\w*?)\s*=(.*)/; + my $comment = $1; # whether or not this log message has been commented out + my $scope = $2; # whether the identifier is public or internal + my $id = $3; # identifier is everything up to '=' + my $value = $4; # rest is actual resource string value - PrintPerf("\nPERF: checking string id values\n"); - foreach my $id (keys(%ids)) + if ($comment eq "") # the id is not commented out { - my $length = length($id); # get length of the id - my $stringvalue = substr ($ids{$id}[2], 2); # remove quote char at start of string - my $stringid = substr($stringvalue, 0, $length); # get prefix of string value - if (not $id eq $stringid) - { - PrintError("string name ($id) is not the same as it's value: $stringid \n \n"); - } - + $dirhash{$directory}{$id} = [0, $value]; + } + else { + $commentedids{$id} = 1; } - - PrintPerf("\nPERF: done reading resources\n"); + + } + close(RES) or die "can't close $resources_txt: $!"; PrintPerf("\nPERF: Open Files\n"); @@ -324,9 +228,9 @@ sub FindDirs { } } + # find all the files in the current directory find(\&FindFilenames, $directory); - PrintPerf("\nPERF: reading and processing source files\n"); foreach my $file (@filenames) { $file =~ /$CROP_FILE_PATH_AT(.*)/; @@ -341,45 +245,87 @@ sub FindDirs { } close(FIL) or die "can't close $file: $!"; - # find all call sites and EnsureArgCountCorrect + # find all call sites my $rest = $filestring; while ($rest =~ /LogMessages\.(\w+)/g) { my $id = $1; - if (defined $ids{$id}) # sometimes there will be commented-out code with LogMessages.ThisIDDoesntExistAnymore + if (defined $allids{$id}) + { + $allids{$id}++; # increment the number of references to this id + } + else { - $ids{$id}[0]++; # increment number-references-to-this-id + $allids{$id} = 1; } } } - PrintPerf("\nPERF: done reading and processing source files\n"); - { - PrintPerf("\nDone processing files\n"); +} + +# go through all the directories again to discover unused, mismatching, and/or duplicate log message ids +foreach my $directory (keys(%dirhash)) +{ + my $resources_txt = $directory . "/LogMessages.cs"; + PrintPerf("\nPERF: starting script\n"); + PrintPerf("\nPERF: Analyzing file: $resources_txt\n"); + + Print("$resources_txt\n\n"); + PrintPerf("\nPERF: reading resources\n"); + + PrintPerf("\nPERF: checking string id values\n"); - my $numUnreferencedIds = 0; - foreach my $id (keys(%ids)) + # go through all log ids in this directory + foreach my $id(keys %{ $dirhash{$directory} }) + { + # if we found a commented out log message with the same id + if (defined($commentedids{$id})) { - my $n = $ids{$id}[0]; - if ($n == 0) - { - PrintError("$id was referenced in $n files\n"); - $numUnreferencedIds++; - } + PrintError("\nSame id ($id) is reused. \n\n"); } - Print("\n$numUnreferencedIds identifiers were unreferenced\n\n"); + + # go through each directory that we've processed so far and check for duplicates and reused log messages + foreach my $directory2 (keys(%dirhash)) + { + if (grep {$_ eq $id} keys %{ $dirhash{$directory2}} ) + { + if (not $directory eq $directory2) + { + PrintError("\nSame id ($id) is reused in the LogMessages.cs file of both: \n $directory \n and \n $directory2 \n \n"); + } + } + } + + CountArgs($id, $dirhash{$directory}{$id}[1]); + VerifyNumBraces($id, $dirhash{$directory}{$id}[1]); + my $length = length($id); # get length of the log message id + my $stringvalue = substr ($dirhash{$directory}{$id}[1], 2); # remove quote char at start of string + my $stringid = substr($stringvalue, 0, $length); # get prefix of string value + if (not $id eq $stringid) + { + PrintError("string name ($id) is not the same as it's value: $stringid \n \n"); + } + } - if ($ERRORS_ONLY_MODE and $THERE_ARE_ERRORS) - { - PrintError("\n"); - PrintError("There were errors checking ProperUsage of resources.txt!\n"); - PrintError("You must fix the above errors before you can build.\n"); - PrintError("See ndp\\indigo\\tools\\Resources\\ProperUsage\\README.txt for details if you need help.\n"); - exit 1; + PrintPerf("\nPERF: done reading resources\n"); + + PrintPerf("\nDone processing files\n"); + + my $numUnreferencedIds = 0; + foreach my $id(sort keys %{ $dirhash{$directory} }) + { + # if the log message id has not been referenced anywhere + if (not defined($allids{$id})) + { + PrintError("$id was referenced in 0 files\n"); + $numUnreferencedIds++; + } } + + Print("\n$numUnreferencedIds identifiers were unreferenced\n\n"); Print("--------------\n\n"); }