Completed
Pull Request — master (#11)
by Matt
04:56
created

SAMLHelper::redirect()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 13
nc 6
nop 3
dl 0
loc 21
rs 9.8333
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\SAML\Helpers;
4
5
use Exception;
6
use Psr\Log\LoggerInterface;
7
use SilverStripe\Control\Director;
8
use SilverStripe\Control\HTTPRequest;
9
use SilverStripe\Control\HTTPResponse_Exception;
10
use SilverStripe\Control\RequestHandler;
11
use SilverStripe\Core\Injector\Injectable;
12
use SilverStripe\Core\Injector\Injector;
13
use SilverStripe\SAML\Authenticators\SAMLLoginHandler;
14
use SilverStripe\SAML\Control\SAMLController;
15
use SilverStripe\SAML\Services\SAMLConfiguration;
16
use OneLogin_Saml2_Auth;
17
18
/**
19
 * Class SAMLHelper
20
 *
21
 * SAMLHelper acts as a simple wrapper for the OneLogin implementation, so that we can configure
22
 * and inject it via the config system.
23
 */
24
class SAMLHelper
25
{
26
    use Injectable;
27
28
    /**
29
     * @var array
30
     */
31
    private static $dependencies = [
0 ignored issues
show
introduced by
The private property $dependencies is not used, and could be removed.
Loading history...
32
        'SAMLConfService' => '%$' . SAMLConfiguration::class,
33
    ];
34
35
    /**
36
     * @var SAMLConfiguration
37
     */
38
    public $SAMLConfService;
39
40
    /**
41
     * @return OneLogin_Saml2_Auth
42
     */
43
    public function getSAMLauth()
44
    {
45
        $samlConfig = $this->SAMLConfService->asArray();
46
        return new OneLogin_Saml2_Auth($samlConfig);
47
    }
48
49
    /**
50
     * Create a SAML AuthN request and send the user off to the identity provider (IdP) to get authenticated. This
51
     * method does not check to see if the user is already authenticated, that is the responsibility of the caller.
52
     *
53
     * Note: This method will *never* return via normal control flow - instead one of two things will happen:
54
     * - The user will be forcefully & immediately redirected to the IdP to get authenticated, OR
55
     * - A HTTPResponse_Exception is thrown because php-saml encountered an error while generating a valid AuthN request
56
     *
57
     * @param RequestHandler $requestHandler In case of error, we require a RequestHandler to throw errors from
58
     * @param HTTPRequest $request The currently active request (used to retrieve session)
59
     * @param string|null $backURL The URL to return to after successful SAML authentication (@see SAMLController)
60
     * @throws HTTPResponse_Exception
61
     * @see SAMLLoginHandler::doLogin() How the SAML login form handles this
62
     * @see SAMLController::acs() How the response is processed after the user is returned from the IdP
63
     * @return void This function will never return via normal control flow (see above).
64
     */
65
    public function redirect(RequestHandler $requestHandler = null, HTTPRequest $request = null, $backURL = null)
66
    {
67
        // $data is not used - the form is just one button, with no fields.
68
        $auth = $this->getSAMLAuth();
69
70
        if ($request) {
71
            $request->getSession()->set('BackURL', $backURL);
72
            $request->getSession()->save($request);
73
        }
74
75
        try {
76
            $auth->login(Director::absoluteBaseURL().'saml/');
77
        } catch (Exception $e) {
78
            /** @var LoggerInterface $logger */
79
            $logger = Injector::inst()->get(LoggerInterface::class);
80
            $logger->error(sprintf('[code:%s] Error during SAMLHelper->redirect: %s', $e->getCode(), $e->getMessage()));
81
82
            if ($requestHandler) {
83
                $requestHandler->httpError(400);
84
            } else {
85
                throw new HTTPResponse_Exception(null, 400);
86
            }
87
        }
88
    }
89
90
    /**
91
     * Checks if the string is a valid guid in the format of A98C5A1E-A742-4808-96FA-6F409E799937
92
     *
93
     * @param  string $guid
94
     * @return bool
95
     */
96
    public function validGuid($guid)
97
    {
98
        if (preg_match('/^[A-Z0-9]{8}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{12}?$/', $guid)) {
99
            return true;
100
        }
101
        return false;
102
    }
103
104
    /**
105
     * @param  string $object_guid
106
     * @return string
107
     */
108
    public function binToStrGuid($object_guid)
109
    {
110
        $hex_guid = bin2hex($object_guid);
111
        $hex_guid_to_guid_str = '';
112
        for ($k = 1; $k <= 4; ++$k) {
113
            $hex_guid_to_guid_str .= substr($hex_guid, 8 - 2 * $k, 2);
114
        }
115
        $hex_guid_to_guid_str .= '-';
116
        for ($k = 1; $k <= 2; ++$k) {
117
            $hex_guid_to_guid_str .= substr($hex_guid, 12 - 2 * $k, 2);
118
        }
119
        $hex_guid_to_guid_str .= '-';
120
        for ($k = 1; $k <= 2; ++$k) {
121
            $hex_guid_to_guid_str .= substr($hex_guid, 16 - 2 * $k, 2);
122
        }
123
        $hex_guid_to_guid_str .= '-' . substr($hex_guid, 16, 4);
124
        $hex_guid_to_guid_str .= '-' . substr($hex_guid, 20);
125
        return strtoupper($hex_guid_to_guid_str);
126
    }
127
}
128