Completed
Push — feature/refactor-gateway-contr... ( 4996d0...48680d )
by
unknown
02:33
created

ConsumeAssertionService   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 124
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 15

Importance

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

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
B consumeAssertion() 0 74 7
A getServiceProvider() 0 4 1
1
<?php
2
3
namespace Surfnet\StepupGateway\SamlStepupProviderBundle\Service;
4
5
use Exception;
6
use Psr\Log\LoggerInterface;
7
use Surfnet\SamlBundle\Http\PostBinding;
8
use Surfnet\SamlBundle\Monolog\SamlAuthenticationLogger;
9
use Surfnet\StepupGateway\GatewayBundle\Entity\ServiceProvider;
10
use Surfnet\StepupGateway\GatewayBundle\Exception\ResponseFailureException;
11
use Surfnet\StepupGateway\GatewayBundle\Saml\AssertionAdapter;
12
use Surfnet\StepupGateway\GatewayBundle\Saml\Exception\UnknownInResponseToException;
13
use Surfnet\StepupGateway\SamlStepupProviderBundle\Exception\InvalidSubjectException;
14
use Surfnet\StepupGateway\SamlStepupProviderBundle\Exception\SecondfactorVerfificationRequiredException;
15
use Surfnet\StepupGateway\SamlStepupProviderBundle\Provider\ConnectedServiceProviders;
16
use Surfnet\StepupGateway\SamlStepupProviderBundle\Provider\Provider;
17
use Surfnet\StepupGateway\SamlStepupProviderBundle\Saml\ProxyResponseFactory;
18
use Symfony\Component\HttpFoundation\Request;
19
20
/**
21
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
22
 */
23
class ConsumeAssertionService
24
{
25
    /** @var LoggerInterface */
26
    private $logger;
27
28
    /** @var SamlAuthenticationLogger */
29
    private $samlLogger;
30
31
    /** @var PostBinding */
32
    private $postBinding;
33
34
    /** @var ConnectedServiceProviders */
35
    private $connectedServiceProviders;
36
37
    /**
38
     * ConsumeAssertionService constructor.
39
     * @param LoggerInterface $logger
40
     * @param SamlAuthenticationLogger $samlLogger
41
     * @param PostBinding $postBinding
42
     * @param ConnectedServiceProviders $connectedServiceProviders
43
     */
44
    public function __construct(
45
        LoggerInterface $logger,
46
        SamlAuthenticationLogger $samlLogger,
47
        PostBinding $postBinding,
48
        ConnectedServiceProviders $connectedServiceProviders
49
    ) {
50
        $this->logger = $logger;
51
        $this->samlLogger = $samlLogger;
52
        $this->postBinding = $postBinding;
53
        $this->connectedServiceProviders = $connectedServiceProviders;
54
    }
55
56
    /**
57
     * @param Provider $provider
58
     * @param Request $httpRequest
59
     * @param ProxyResponseFactory $proxyResponseFactory
60
     * @return \SAML2\Response
61
     * @throws Exception
62
     */
63
    public function consumeAssertion(Provider $provider, Request $httpRequest, ProxyResponseFactory $proxyResponseFactory)
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 122 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...
64
    {
65
        $stateHandler = $provider->getStateHandler();
66
        $originalRequestId = $stateHandler->getRequestId();
67
68
        $logger = $this->samlLogger->forAuthentication($originalRequestId);
69
70
        $action = $stateHandler->hasSubject() ? 'Second Factor Verification' : 'Proxy Response';
71
        $logger->notice(
72
            sprintf('Received SAMLResponse, attempting to process for %s', $action)
73
        );
74
75
        try {
76
            $assertion = $this->postBinding->processResponse(
77
                $httpRequest,
78
                $provider->getRemoteIdentityProvider(),
79
                $provider->getServiceProvider()
80
            );
81
        } catch (Exception $exception) {
82
            $message = sprintf('Could not process received Response, error: "%s"', $exception->getMessage());
83
            $logger->error($message);
84
85
            throw new ResponseFailureException($message);
86
        }
87
88
        $adaptedAssertion = new AssertionAdapter($assertion);
89
        $expectedResponse = $stateHandler->getGatewayRequestId();
90
        if (!$adaptedAssertion->inResponseToMatches($expectedResponse)) {
91
            throw new UnknownInResponseToException(
92
                $adaptedAssertion->getInResponseTo(),
93
                $expectedResponse
94
            );
95
        }
96
97
        $authenticatedNameId = $assertion->getNameId();
98
        $isSubjectRequested = $stateHandler->hasSubject();
99
        if ($isSubjectRequested && ($stateHandler->getSubject() !== $authenticatedNameId->value)) {
100
            $message = sprintf(
101
                'Requested Subject NameID "%s" and Response NameID "%s" do not match',
102
                $stateHandler->getSubject(),
103
                $authenticatedNameId->value
104
            );
105
            $logger->critical($message);
106
107
            throw new InvalidSubjectException($message);
108
        }
109
110
        $logger->notice('Successfully processed SAMLResponse');
111
112
        if ($stateHandler->secondFactorVerificationRequested()) {
113
            $message = 'Second Factor verification was requested and was successful, forwarding to SecondFactor handling';
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 122 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...
114
            $logger->notice($message);
115
116
            throw new SecondfactorVerfificationRequiredException($message);
117
        }
118
119
        $targetServiceProvider = $this->getServiceProvider($stateHandler->getRequestServiceProvider());
120
121
        $response = $proxyResponseFactory->createProxyResponse(
122
            $assertion,
123
            $targetServiceProvider->determineAcsLocation(
124
                $stateHandler->getRequestAssertionConsumerServiceUrl(),
125
                $this->logger
126
            )
127
        );
128
129
        $logger->notice(sprintf(
130
            'Responding to request "%s" with response based on response from the remote IdP with response "%s"',
131
            $stateHandler->getRequestId(),
132
            $response->getId()
133
        ));
134
135
        return $response;
136
    }
137
138
    /**
139
     * @param string $serviceProvider
140
     * @return ServiceProvider
141
     */
142
    private function getServiceProvider($serviceProvider)
143
    {
144
        return $this->connectedServiceProviders->getConfigurationOf($serviceProvider);
145
    }
146
}
147