Completed
Push — feature/use-authn-request-acs-... ( e65869...994cc5 )
by
unknown
05:35
created

ServiceProvider::determineAcsLocationForAdfs()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 17
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 7
nc 3
nop 1
1
<?php
2
3
/**
4
 * Copyright 2014 SURFnet bv
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
namespace Surfnet\StepupGateway\GatewayBundle\Entity;
20
21
use Psr\Log\LoggerInterface;
22
use Surfnet\SamlBundle\Entity\ServiceProvider as BaseServiceProvider;
23
use Surfnet\StepupGateway\GatewayBundle\Exception\InvalidArgumentException;
24
use Surfnet\StepupGateway\SecondFactorOnlyBundle\Adfs\Exception\AcsLocationNotAllowedException;
25
26
class ServiceProvider extends BaseServiceProvider
27
{
28
    /**
29
     * @return bool
30
     */
31
    public function mayUseGateway()
32
    {
33
        return !$this->mayUseSecondFactorOnly();
34
    }
35
36
    /**
37
     * @return bool
38
     */
39
    public function mayUseSecondFactorOnly()
40
    {
41
        return (bool) $this->get('secondFactorOnly', false);
42
    }
43
44
    /**
45
     * @param string $nameId
46
     * @return bool
47
     */
48
    public function isAllowedToUseSecondFactorOnlyFor($nameId)
49
    {
50
        if (!is_string($nameId)) {
51
            throw InvalidArgumentException::invalidType('string', 'nameId', $nameId);
52
        }
53
54
        if (empty($nameId)) {
55
            return false;
56
        }
57
58
        if (!$this->mayUseSecondFactorOnly()) {
59
            return false;
60
        }
61
62
        $nameIdPatterns = $this->get('secondFactorOnlyNameIdPatterns');
63
        foreach ($nameIdPatterns as $nameIdPattern) {
64
            if ((bool) preg_match('#^' . strtr(preg_quote($nameIdPattern, '#'), ['\*' => '.*']) . '$#', $nameId)) {
65
                return true;
66
            }
67
        }
68
        return false;
69
    }
70
71
    /**
72
     * Determine the ACS location to send the response to.
73
     *
74
     * The get getAssertionConsumerUrl() method returns a trusted ACS location
75
     * for this service provider. This value is set when the service provider
76
     * is "internal", for example when it is configured in yaml
77
     * configuration.
78
     *
79
     * Methods like Surfnet\SamlBundle\Http\PostBinding::processResponse use
80
     * this trusted value. When the ServiceProvider is external, this value is
81
     * empty and the ACS location found in the AuthnRequest should be used, if
82
     * it matches one of the configured allowed ACS locations for the service
83
     * provider. This methods checks if a given URL matches the allowed URLs.
84
     *
85
     * @param $acsLocationInAuthnRequest
86
     * @param LoggerInterface $logger Optional
0 ignored issues
show
Documentation introduced by
Should the type for parameter $logger not be null|LoggerInterface?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
87
     * @return string
88
     */
89
    public function determineAcsLocation($acsLocationInAuthnRequest, LoggerInterface $logger = null)
90
    {
91
        // List of allowed ACS locations configured in middleware.
92
        $allowedAcsLocations = $this->get('allowedAcsLocations');
93
94
        if (in_array($acsLocationInAuthnRequest, $allowedAcsLocations)) {
95
            return $acsLocationInAuthnRequest;
96
        }
97
98
        if ($logger !== null) {
99
            $logger->warning(
100
                sprintf(
101
                    'AuthnRequest requests ACS location "%s" but it is not configured in the list of allowed ACS locations',
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 124 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
102
                    $acsLocationInAuthnRequest
103
                )
104
            );
105
        }
106
107
        return reset($allowedAcsLocations);
108
    }
109
110
    /**
111
     * Determine the ACS location for ADFS to send the response to.
112
     *
113
     * This method is similar to determineAcsLocation(), but does not check
114
     * for the requested ACS location to be identical to one of the configured
115
     * ACS locations, but only if matches the first part of an allowed URL.
116
     *
117
     * For example, ADFS might send an ACS location like:
118
     *
119
     *     https://example.com/consume-assertion?key=value
120
     *
121
     * Above URL is allowed if one of the configured URLs is:
122
     *
123
     *     https://example.com/consume-assertion
124
     *
125
     * Or:
126
     *
127
     *     https://example.com/consume
128
     *
129
     *
130
     * @param $acsLocationInAuthnRequest
131
     * @return string
132
     */
133
    public function determineAcsLocationForAdfs($acsLocationInAuthnRequest)
134
    {
135
        // List of allowed ACS locations configured in middleware.
136
        $allowedAcsLocations = $this->get('allowedAcsLocations');
137
138
        foreach ($allowedAcsLocations as $allowedAcsLocation) {
139
            if (strpos($acsLocationInAuthnRequest, $allowedAcsLocation) === 0) {
140
                return $acsLocationInAuthnRequest;
141
            }
142
        }
143
144
        // The exception listener will log relevant information to the log.
145
146
        throw new AcsLocationNotAllowedException(
147
            $acsLocationInAuthnRequest
148
        );
149
    }
150
}
151