Completed
Pull Request — 0.3.x (#4)
by Alexandru-Daniel
04:53
created

SingleSignOnAuthenticationEntryPoint   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 117
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 0%

Importance

Changes 4
Bugs 1 Features 2
Metric Value
wmc 11
c 4
b 1
f 2
lcom 1
cbo 6
dl 0
loc 117
ccs 0
cts 57
cp 0
rs 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
C start() 0 87 10
1
<?php
2
3
namespace Krtv\Bundle\SingleSignOnServiceProviderBundle\EntryPoint;
4
5
use Krtv\Bundle\SingleSignOnServiceProviderBundle\Context\AuthenticationContext;
6
use Krtv\Bundle\SingleSignOnServiceProviderBundle\Context\AuthenticationContextFactory;
7
use Symfony\Component\HttpFoundation\ParameterBag;
8
use Symfony\Component\HttpFoundation\Request;
9
use Symfony\Component\HttpKernel\UriSigner;
10
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
11
use Symfony\Component\Security\Core\Exception\AuthenticationException;
12
use Symfony\Component\Security\Http\HttpUtils;
13
14
/**
15
 * Class SingleSignOnAuthenticationEntryPoint
16
 * @package Krtv\Bundle\SingleSignOnServiceProviderBundle\EntryPoint
17
 */
18
class SingleSignOnAuthenticationEntryPoint implements AuthenticationEntryPointInterface
19
{
20
    /**
21
     * @var AuthenticationContextFactory
22
     */
23
    private $contextFactory;
24
25
    /**
26
     * @var HttpUtils
27
     */
28
    private $httpUtils;
29
30
    /**
31
     * @var UriSigner
32
     */
33
    private $uriSigner;
34
35
    /**
36
     * @param AuthenticationContextFactory $contextFactory
37
     * @param UriSigner $signer
38
     * @param HttpUtils $httpUtils
39
     */
40
    public function __construct(AuthenticationContextFactory $contextFactory, UriSigner $signer, HttpUtils $httpUtils)
41
    {
42
        $this->contextFactory = $contextFactory;
43
        $this->httpUtils      = $httpUtils;
44
        $this->uriSigner      = $signer;
45
    }
46
47
    public function start(Request $request, AuthenticationException $authException = null)
48
    {
49
        $context = $request->attributes->get($this->contextFactory->getAttribute()); /* @var AuthenticationContext $context */
50
        $options = $context->getOptions();
51
52
        $targetPathParameter    = $options->get('target_path_parameter');
53
        $failurePathParameter   = $options->get('failure_path_parameter');
54
55
        $serviceParameter       = $options->get('sso_service_parameter');
56
        $serviceExtraParameter  = $options->get('sso_service_extra_parameter');
57
58
        $loginRequiredParameter = $options->get('sso_login_required_parameter');
59
60
        $scheme = $options->get('sso_scheme');
61
        $host   = $options->get('sso_host');
62
        $path   = $options->get('sso_path');
63
64
        // OTP validate callback should point to /otp/validate/ route on service provider
65
        // For example: http://service.provider/otp/validate/
66
        $otpValidateUrl = $context->getOtpValidationPath($request);
67
68
        // Target path is a URL or path to previous URL or it
69
        // should be an any route which user should visit after OTP valid check.
70
        $targetUrl      = $context->getTargetPath($request);
71
72
        // Add extra parameters to Target URL which are marked as proxy parameters.
73
        if ($context->getServiceProxy()->count()) {
74
            if (strpos($targetUrl, '?') === false) {
75
                $targetUrl .= '?';
76
            }
77
78
            $params = array();
79
            foreach ($context->getServiceProxy() as $name => $value) {
80
                $params[$name] = $context->getServiceExtra()->get($name);
81
            }
82
83
            $targetUrl .= http_build_query($params);
84
        }
85
86
        // Sign Target URL to be able verify signature later
87
        $targetUrl = $this->uriSigner->sign($targetUrl);
88
89
        // User will be redirected to this route if he isn't authenticated on identity provider
90
        // or if identity provider returned invalid response on OTP check.
91
        $failureUrl     = $context->getFailurePath($request);
92
93
        // Failure URL should contain Target URL to be able catch it if user came back from identity provider
94
        if ($failureUrl) {
95
            if (strpos($failureUrl, '?') === false) {
96
                $separator = '?';
97
            } else {
98
                $separator = '&';
99
            }
100
101
            $failureUrl .= sprintf('%s%s=%s', $separator, $targetPathParameter, rawurlencode($targetUrl));
102
103
            // If failure url is the same with current host we add a login_required=1 parameter
104
            // To be able to suppress SSO Authentication attempt.
105
            // Make sure that your failure url is accessible as guest.
106
            if (strpos($failureUrl, $request->getSchemeAndHttpHost()) === 0) {
107
                $failureUrl .= sprintf('&%s=%s', $loginRequiredParameter, $options->get('sso_login_required'));
108
            }
109
        }
110
111
        $redirectUri = sprintf('%s/?%s=%s', rtrim($otpValidateUrl, '/'), $targetPathParameter, rawurlencode($targetUrl));
112
113
        // Build SSO login URL.
114
        $redirectUri = sprintf('%s://%s%s/?%s=%s', $scheme, $host, rtrim($path, '/'), $targetPathParameter, rawurlencode($redirectUri));
115
        $redirectUri = sprintf('%s&%s=%s', $redirectUri, $failurePathParameter, rawurlencode($failureUrl));
116
117
        // Append service provider name to root sso login url to be able determine it on identity provider.
118
        if ($context->getService()) {
119
            $redirectUri .= sprintf('&%s=%s', $serviceParameter, $context->getService());
120
        }
121
122
        // Append all extra parameters to root sso login url
123
        if ($context->getService() && $context->getServiceExtra()->count()) {
124
            $redirectUri .= sprintf('&%s', http_build_query(array(
125
                $serviceExtraParameter => $context->getServiceExtra()->all()
126
            )));
127
        }
128
129
        // Sign data
130
        $redirectUri = $this->uriSigner->sign($redirectUri);
131
132
        return $this->httpUtils->createRedirectResponse($request, $redirectUri);
133
    }
134
}
135