Assertion::addValidators()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 9.552
c 0
b 0
f 0
nc 2
cc 2
nop 0
1
<?php
2
3
4
namespace flipbox\saml\core\validators;
5
6
use flipbox\saml\core\AbstractPlugin;
7
use flipbox\saml\core\helpers\SecurityHelper;
8
use flipbox\saml\core\records\AbstractProvider;
9
use SAML2\Assertion as SamlAssertion;
10
use SAML2\Assertion\Validation\AssertionConstraintValidator;
11
use SAML2\Assertion\Validation\ConstraintValidator;
12
use SAML2\Assertion\Validation\Result;
13
use SAML2\Assertion\Validation\SubjectConfirmationConstraintValidator;
14
use SAML2\Configuration\Destination;
15
use SAML2\EncryptedAssertion;
16
17
class Assertion
18
{
19
    /**
20
     * @var AbstractProvider
21
     */
22
    private $identityProvider;
23
    /**
24
     * @var AbstractProvider
25
     */
26
    private $serviceProvider;
27
    /**
28
     * @var \SAML2\Response
29
     */
30
    private $response;
31
    private $validators;
32
33
    /**
34
     * Assertion constructor.
35
     * @param \SAML2\Response $response
36
     * @param AbstractProvider $identityProvider
37
     * @param AbstractProvider $serviceProvider
38
     * @throws \Exception
39
     */
40
    public function __construct(
41
        \SAML2\Response $response,
42
        AbstractProvider $identityProvider,
43
        AbstractProvider $serviceProvider
44
    ) {
45
        $this->identityProvider = $identityProvider;
46
        $this->serviceProvider = $serviceProvider;
47
        $this->response = $response;
48
49
        $this->addValidators();
50
    }
51
52
    /**
53
     * @throws \Exception
54
     */
55
    private function addValidators()
56
    {
57
        $this->validators = [
58
            new ConstraintValidator\NotBefore(),
59
            new ConstraintValidator\NotOnOrAfter(),
60
            new ConstraintValidator\SessionNotOnOrAfter(),
61
            new ConstraintValidator\SubjectConfirmationMethod(),
62
            new ConstraintValidator\SubjectConfirmationNotBefore(),
63
            new ConstraintValidator\SubjectConfirmationNotOnOrAfter(),
64
            new ConstraintValidator\SubjectConfirmationRecipientMatches(
65
                new Destination(
66
                    $this->serviceProvider->firstSpAcsService()->getLocation()
67
                )
68
            ),
69
            new ConstraintValidator\SubjectConfirmationResponseToMatches(
70
                $this->response
71
            ),
72
73
        ];
74
        if ($keyStore = $this->identityProvider->signingXMLSecurityKeyStore()) {
75
            $this->validators[] = new SignedElement($keyStore);
76
        }
77
    }
78
79
    /**
80
     * @param $assertion
81
     * @return Result
82
     */
83
    public function validate($assertion): Result
84
    {
85
        // Decrypt if needed
86
        if ($assertion instanceof EncryptedAssertion) {
87
            $assertion = SecurityHelper::decryptAssertion(
88
                $assertion,
89
                $this->serviceProvider->keychain->getDecryptedKey()
90
            );
91
        }
92
93
        /** @var SamlAssertion $assertion */
94
95
        $result = new Result();
96
97
        foreach ($this->validators as $validator) {
98
            if ($validator instanceof SubjectConfirmationConstraintValidator) {
99
                $this->validateSubjectConfirmations(
100
                    $validator,
101
                    $assertion->getSubjectConfirmation(),
102
                    $result
103
                );
104
            } else {
105
106
                /** @var SignedElement|AssertionConstraintValidator $validator */
107
                $validator->validate($assertion, $result);
108
            }
109
            \Craft::info(
110
                sprintf(
111
                    "%s validation errors: %s",
112
                    \get_class($validator),
113
                    \json_encode($result->getErrors())
114
                ),
115
                AbstractPlugin::SAML_CORE_HANDLE
116
            );
117
        }
118
119
        return $result;
120
    }
121
122
    /**
123
     * @param array $subjectConfirmations
124
     * @param Result $result
125
     */
126
    protected function validateSubjectConfirmations(
127
        SubjectConfirmationConstraintValidator $validator,
128
        array $subjectConfirmations,
129
        Result $result
130
    ) {
131
        foreach ($subjectConfirmations as $subjectConfirmation) {
132
            $validator->validate($subjectConfirmation, $result);
133
        }
134
    }
135
}
136