Completed
Push — master ( 4b394d...0ca4f0 )
by Damien
09:55
created

Assertion   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 125
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 17

Importance

Changes 0
Metric Value
wmc 9
lcom 1
cbo 17
dl 0
loc 125
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 1
A addValidators() 0 23 2
A validate() 0 41 4
A validateSubjectConfirmations() 0 10 2
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
18
class Assertion
19
{
20
    /**
21
     * @var AbstractProvider
22
     */
23
    private $identityProvider;
24
    /**
25
     * @var AbstractProvider
26
     */
27
    private $serviceProvider;
28
    /**
29
     * @var \SAML2\Response
30
     */
31
    private $response;
32
    private $validators;
33
34
    /**
35
     * Assertion constructor.
36
     * @param \SAML2\Response $response
37
     * @param AbstractProvider $identityProvider
38
     * @param AbstractProvider $serviceProvider
39
     * @throws \Exception
40
     */
41
    public function __construct(
42
        \SAML2\Response $response,
43
        AbstractProvider $identityProvider,
44
        AbstractProvider $serviceProvider
45
    )
46
    {
47
        $this->identityProvider = $identityProvider;
48
        $this->serviceProvider = $serviceProvider;
49
        $this->response = $response;
50
51
        $this->addValidators();
52
    }
53
54
    /**
55
     * @throws \Exception
56
     */
57
    private function addValidators()
58
    {
59
        $this->validators = [
60
            new ConstraintValidator\NotBefore(),
61
            new ConstraintValidator\NotOnOrAfter(),
62
            new ConstraintValidator\SessionNotOnOrAfter(),
63
            new ConstraintValidator\SubjectConfirmationMethod(),
64
            new ConstraintValidator\SubjectConfirmationNotBefore(),
65
            new ConstraintValidator\SubjectConfirmationNotOnOrAfter(),
66
            new ConstraintValidator\SubjectConfirmationRecipientMatches(
67
                new Destination(
68
                    $this->serviceProvider->firstSpAcsService()->getLocation()
69
                )
70
            ),
71
            new ConstraintValidator\SubjectConfirmationResponseToMatches(
72
                $this->response
73
            ),
74
75
        ];
76
        if ($key = $this->identityProvider->signingXMLSecurityKey()) {
77
            $this->validators[] = new SignedElement($key);
78
        }
79
    }
80
81
    /**
82
     * @param $assertion
83
     * @return Result
84
     */
85
    public function validate($assertion): Result
86
    {
87
        // Decrypt if needed
88
        if ($assertion instanceof EncryptedAssertion) {
89
90
            $assertion = SecurityHelper::decryptAssertion(
91
                $assertion,
92
                $this->serviceProvider->keychain->getDecryptedCertificate()
93
            );
94
        }
95
96
        /** @var SamlAssertion $assertion */
97
98
        $result = new Result();
99
100
        foreach ($this->validators as $validator) {
101
102
            if ($validator instanceof SubjectConfirmationConstraintValidator) {
103
                $this->validateSubjectConfirmations(
104
                    $validator,
105
                    $assertion->getSubjectConfirmation(),
106
                    $result
107
                );
108
            } else {
109
110
                /** @var SignedElement|AssertionConstraintValidator $validator */
111
                $validator->validate($assertion, $result);
112
            }
113
            \Craft::debug(
114
                sprintf(
115
                    "%s validation errors: %s",
116
                    \get_class($validator),
117
                    \json_encode($result->getErrors())
118
                ),
119
                AbstractPlugin::SAML_CORE_HANDLE
120
            );
121
        }
122
123
        return $result;
124
125
    }
126
127
    /**
128
     * @param array $subjectConfirmations
129
     * @param Result $result
130
     */
131
    protected function validateSubjectConfirmations(
132
        SubjectConfirmationConstraintValidator $validator,
133
        array $subjectConfirmations,
134
        Result $result
135
    )
136
    {
137
        foreach ($subjectConfirmations as $subjectConfirmation) {
138
            $validator->validate($subjectConfirmation, $result);
139
        }
140
    }
141
142
}