Completed
Push — feature/refactor-gateway-contr... ( 48680d...09b176 )
by
unknown
03:25
created

ConsumeAssertionService::consumeAssertion()   B

Complexity

Conditions 7
Paths 10

Size

Total Lines 74

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 74
rs 7.6339
c 0
b 0
f 0
cc 7
nc 10
nop 3

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Surfnet\StepupGateway\SamlStepupProviderBundle\Service\Gateway;
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
     * Process an assertion received from a remote GSSP application.
58
     *
59
     * There are two possible outcomes for a valid flow:
60
     *
61
     *  1. in case of registration: a SAMLResponse is returned
62
     *  2. in case of verification: a SecondfactorVerfificationRequiredException exception is thrown
63
     *
64
     * @param Provider $provider
65
     * @param Request $httpRequest
66
     * @param ProxyResponseFactory $proxyResponseFactory
67
     * @return \SAML2\Response
68
     * @throws Exception
69
     */
70
    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...
71
    {
72
        $stateHandler = $provider->getStateHandler();
73
        $originalRequestId = $stateHandler->getRequestId();
74
75
        $logger = $this->samlLogger->forAuthentication($originalRequestId);
76
77
        $action = $stateHandler->hasSubject() ? 'Second Factor Verification' : 'Proxy Response';
78
        $logger->notice(
79
            sprintf('Received SAMLResponse, attempting to process for %s', $action)
80
        );
81
82
        try {
83
            $assertion = $this->postBinding->processResponse(
84
                $httpRequest,
85
                $provider->getRemoteIdentityProvider(),
86
                $provider->getServiceProvider()
87
            );
88
        } catch (Exception $exception) {
89
            $message = sprintf('Could not process received Response, error: "%s"', $exception->getMessage());
90
            $logger->error($message);
91
92
            throw new ResponseFailureException($message);
93
        }
94
95
        $adaptedAssertion = new AssertionAdapter($assertion);
96
        $expectedResponse = $stateHandler->getGatewayRequestId();
97
        if (!$adaptedAssertion->inResponseToMatches($expectedResponse)) {
98
            throw new UnknownInResponseToException(
99
                $adaptedAssertion->getInResponseTo(),
100
                $expectedResponse
101
            );
102
        }
103
104
        $authenticatedNameId = $assertion->getNameId();
105
        $isSubjectRequested = $stateHandler->hasSubject();
106
        if ($isSubjectRequested && ($stateHandler->getSubject() !== $authenticatedNameId->value)) {
107
            $message = sprintf(
108
                'Requested Subject NameID "%s" and Response NameID "%s" do not match',
109
                $stateHandler->getSubject(),
110
                $authenticatedNameId->value
111
            );
112
            $logger->critical($message);
113
114
            throw new InvalidSubjectException($message);
115
        }
116
117
        $logger->notice('Successfully processed SAMLResponse');
118
119
        if ($stateHandler->secondFactorVerificationRequested()) {
120
            $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...
121
            $logger->notice($message);
122
123
            throw new SecondfactorVerfificationRequiredException($message);
124
        }
125
126
        $targetServiceProvider = $this->getServiceProvider($stateHandler->getRequestServiceProvider());
127
128
        $response = $proxyResponseFactory->createProxyResponse(
129
            $assertion,
130
            $targetServiceProvider->determineAcsLocation(
131
                $stateHandler->getRequestAssertionConsumerServiceUrl(),
132
                $this->logger
133
            )
134
        );
135
136
        $logger->notice(sprintf(
137
            'Responding to request "%s" with response based on response from the remote IdP with response "%s"',
138
            $stateHandler->getRequestId(),
139
            $response->getId()
140
        ));
141
142
        return $response;
143
    }
144
145
    /**
146
     * @param string $serviceProvider
147
     * @return ServiceProvider
148
     */
149
    private function getServiceProvider($serviceProvider)
150
    {
151
        return $this->connectedServiceProviders->getConfigurationOf($serviceProvider);
152
    }
153
}
154