• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

NIT-Administrative-Systems / SysDev-laravel-soa / 13508657684

24 Feb 2025 09:57PM UTC coverage: 45.13% (-0.1%) from 45.277%
13508657684

Pull #184

github

web-flow
Merge 265b9b845 into a782f5d90
Pull Request #184: Laravel 12 Support

0 of 4 new or added lines in 2 files covered. (0.0%)

1 existing line in 1 file now uncovered.

278 of 616 relevant lines covered (45.13%)

14.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Auth/OAuth2/TokenVerifier/Contract/AbstractAzureTokenVerifier.php
1
<?php
2

3
namespace Northwestern\SysDev\SOA\Auth\OAuth2\TokenVerifier\Contract;
4

5
use Firebase\JWT\JWK;
6
use GuzzleHttp\Client;
7
use Illuminate\Support\Facades\Cache;
8
use Laravel\Socialite\Two\InvalidStateException;
9
use Lcobucci\Clock\SystemClock;
10
use Lcobucci\JWT\Configuration;
11
use Lcobucci\JWT\Signer\Key\InMemory;
12
use Lcobucci\JWT\Signer\Rsa\Sha256;
13
use Lcobucci\JWT\UnencryptedToken;
14
use Lcobucci\JWT\Validation\Constraint;
15
use Lcobucci\JWT\Validation\Constraint\LooseValidAt;
16
use Lcobucci\JWT\Validation\Constraint\SignedWith;
17
use Lcobucci\JWT\Validation\RequiredConstraintsViolated;
18

19
abstract class AbstractAzureTokenVerifier
20
{
21
    public const KEYS_URL = 'https://login.microsoftonline.com/common/discovery/v2.0/keys';
22

23
    /**
24
     * The list of additional constraints to validate the token.
25
     *
26
     * {@see SignedWith} (for valid Microsoft keys) and {@see LooseValidAt} will always be applied.
27
     *
28
     * @return Constraint[]
29
     */
30
    abstract protected function additionalTokenConstraints(): array;
31

32
    /**
33
     * Parses the ID token, validates it with Microsoft's signing keys, and returns it.
34
     *
35
     * This method will download Microsoft's signing keys and cache them briefly.
36
     *
37
     * @throws InvalidStateException
38
     */
39
    public function parseAndVerify(string $jwt): UnencryptedToken
40
    {
41
        $jwtContainer = Configuration::forUnsecuredSigner();
×
42
        $token = $jwtContainer->parser()->parse($jwt);
×
43

44
        $data = $this->loadKeys();
×
45

46
        /**
47
         * This is kind of jank, but the `alg` claim in the JWK is not required by the spec, so Microsoft has opted
48
         * not to include it.
49
         *
50
         * As of v6, the JWT library requires either the alg to be provided -or- a default given, to mitigate
51
         * CVE-2021-46743, a key type confusion attack. The CVE is probably broadly applicable to any implementation
52
         * dealing with these keys missing their `alg` claims.
53
         *
54
         * If Microsoft updates in the future, they will hopefully start providing the `alg` claim on the new keys in
55
         * the keyring. In that case, this will continue to work just fine, since the `alg` claim has priority over
56
         * this default.
57
         *
58
         * @see https://github.com/firebase/php-jwt/issues/498
59
         * @see https://github.com/advisories/GHSA-8xf4-w7qw-pjjw
60
         * @see https://github.com/firebase/php-jwt/issues/351
61
         */
NEW
62
        $defaultAlgorithm = 'RS256';
×
63

NEW
64
        $publicKeys = JWK::parseKeySet($data, $defaultAlgorithm);
×
UNCOV
65
        $kid = $token->headers()->get('kid');
×
66

67
        if (isset($publicKeys[$kid])) {
×
NEW
68
            $publicKey = openssl_pkey_get_details($publicKeys[$kid]->getKeyMaterial());
×
69
            $constraints = [
×
70
                new SignedWith(new Sha256(), InMemory::plainText($publicKey['key'])),
×
71
                new LooseValidAt(SystemClock::fromSystemTimezone()),
×
72
                ...$this->additionalTokenConstraints(),
×
73
            ];
×
74

75
            try {
76
                $jwtContainer->validator()->assert($token, ...$constraints);
×
77

78
                if (! ($token instanceof UnencryptedToken)) {
×
79
                    $type = get_class($token);
×
80
                    throw new InvalidStateException("Expected an UnencryptedToken, got {$type} instead.");
×
81
                }
82

83
                return $token;
×
84
            } catch (RequiredConstraintsViolated $e) {
×
85
                throw new InvalidStateException($e->getMessage());
×
86
            }
87
        }
88

89
        throw new InvalidStateException('Invalid JWT Signature');
×
90
    }
91

92
    private function loadKeys()
93
    {
94
        return Cache::remember('socialite:Azure-JWKSet', 5 * 60, function () {
×
95
            $response = (new Client())->get(self::KEYS_URL);
×
96

97
            return json_decode($response->getBody()->getContents(), true);
×
98
        });
×
99
    }
100
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc