Completed
Pull Request — master (#117)
by Mateusz
07:37
created

SAMLConfiguration::getRequestedAuthnContext()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 36
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 36
rs 8.439
c 0
b 0
f 0
cc 6
eloc 22
nc 6
nop 0
1
<?php
2
/**
3
 * Class SAMLConfiguration
4
 *
5
 * This object's job is to convert configuration from SilverStripe config system
6
 * into an array that can be consumed by the Onelogin SAML implementation.
7
 *
8
 * The configuration tells the IdP and SP how to establish the circle of trust - i.e.
9
 * how to exchange certificates and which endpoints to use (e.g. see SAMLConfiguration::metadata).
10
 *
11
 * https://syncplicity.zendesk.com/hc/en-us/articles/202392814-Single-sign-on-with-ADFS
12
 */
13
class SAMLConfiguration extends Object
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
14
{
15
    /**
16
     * @var bool
17
     */
18
    private static $strict;
0 ignored issues
show
Unused Code introduced by
The property $strict is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
19
20
    /**
21
     * @var bool
22
     */
23
    private static $debug;
0 ignored issues
show
Unused Code introduced by
The property $debug is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
24
25
    /**
26
     * @var array
27
     */
28
    private static $SP;
0 ignored issues
show
Unused Code introduced by
The property $SP is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
29
30
    /**
31
     * @var array
32
     */
33
    private static $IdP;
0 ignored issues
show
Unused Code introduced by
The property $IdP is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
34
35
    /**
36
     * @return array
37
     */
38
    public function asArray()
39
    {
40
        $conf = [];
41
42
        $conf['strict'] = $this->config()->get('strict');
43
        $conf['debug'] = $this->config()->get('debug');
44
45
        // SERVICE PROVIDER SECTION
46
        $sp = $this->config()->get('SP');
47
48
        // set baseurl for SAML messages coming back to the SP
49
        $conf['baseurl'] = $sp['entityId'];
50
51
        $spCertPath = Director::is_absolute($sp['x509cert']) ? $sp['x509cert'] : sprintf('%s/%s', BASE_PATH, $sp['x509cert']);
52
        $spKeyPath = Director::is_absolute($sp['privateKey']) ? $sp['privateKey'] : sprintf('%s/%s', BASE_PATH, $sp['privateKey']);
53
        $conf['sp']['entityId'] = $sp['entityId'];
54
        $conf['sp']['assertionConsumerService'] = [
55
            'url' => $sp['entityId'] . '/saml/acs',
56
            'binding' => OneLogin_Saml2_Constants::BINDING_HTTP_POST
57
        ];
58
        $conf['sp']['NameIDFormat'] = isset($sp['nameIdFormat']) ? $sp['nameIdFormat'] : OneLogin_Saml2_Constants::NAMEID_TRANSIENT;
59
        $conf['sp']['x509cert'] = file_get_contents($spCertPath);
60
        $conf['sp']['privateKey'] = file_get_contents($spKeyPath);
61
62
        // IDENTITY PROVIDER SECTION
63
        $idp = $this->config()->get('IdP');
64
        $conf['idp']['entityId'] = $idp['entityId'];
65
        $conf['idp']['singleSignOnService'] = [
66
            'url' => $idp['singleSignOnService'],
67
            'binding' => OneLogin_Saml2_Constants::BINDING_HTTP_REDIRECT,
68
        ];
69
        if (isset($idp['singleLogoutService'])) {
70
            $conf['idp']['singleLogoutService'] = [
71
                'url' => $idp['singleLogoutService'],
72
                'binding' => OneLogin_Saml2_Constants::BINDING_HTTP_REDIRECT,
73
            ];
74
        }
75
76
        $idpCertPath = Director::is_absolute($idp['x509cert']) ? $idp['x509cert'] : sprintf('%s/%s', BASE_PATH, $idp['x509cert']);
77
        $conf['idp']['x509cert'] = file_get_contents($idpCertPath);
78
79
        // SECURITY SECTION
80
        $security = $this->config()->get('Security');
81
        $signatureAlgorithm = $security['signatureAlgorithm'];
82
        $requestedAuthnContextComparison = $security['requestedAuthnContextComparison'] ?: 'exact';
83
84
        $conf['security'] = [
85
            /** signatures and encryptions offered */
86
            // Indicates that the nameID of the <samlp:logoutRequest> sent by this SP will be encrypted.
87
            'nameIdEncrypted' => true,
88
            // Indicates whether the <samlp:AuthnRequest> messages sent by this SP will be signed. [Metadata of the SP will offer this info]
89
            'authnRequestsSigned' => true,
90
            // Indicates whether the <samlp:logoutRequest> messages sent by this SP will be signed.
91
            'logoutRequestSigned' => true,
92
            // Indicates whether the <samlp:logoutResponse> messages sent by this SP will be signed.
93
            'logoutResponseSigned' => true,
94
            'signMetadata' => false,
95
            /** signatures and encryptions required **/
96
            // Indicates a requirement for the <samlp:Response>, <samlp:LogoutRequest>
97
            // and <samlp:LogoutResponse> elements received by this SP to be signed.
98
            'wantMessagesSigned' => false,
99
            // Indicates a requirement for the <saml:Assertion> elements received by
100
            // this SP to be signed. [Metadata of the SP will offer this info]
101
            'wantAssertionsSigned' => true,
102
            // Indicates a requirement for the NameID received by
103
            // this SP to be encrypted.
104
            'wantNameIdEncrypted' => false,
105
            // Algorithm that the toolkit will use on signing process. Options:
106
            //  - 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
107
            //  - 'http://www.w3.org/2000/09/xmldsig#dsa-sha1'
108
            //  - 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'
109
            //  - 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'
110
            //  - 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512'
111
            'signatureAlgorithm' => $signatureAlgorithm,
112
            // Authentication context.
113
            // Set to false and no AuthContext will be sent in the AuthNRequest,
114
            // Set true or don't present thi parameter and you will get an AuthContext 'exact' 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'
115
            // Set an array with the possible auth context values: array ('urn:oasis:names:tc:SAML:2.0:ac:classes:Password', 'urn:oasis:names:tc:SAML:2.0:ac:classes:X509'),
116
            'requestedAuthnContext' => $this->getrequestedAuthnContext(),
117
            // Allows the authn comparison parameter to be set, defaults to 'exact' if
118
            // the setting is not present.
119
            // better | exact | maximum | minimum
120
            'requestedAuthnContextComparison' => $requestedAuthnContextComparison,
121
            // Indicates if the SP will validate all received xmls.
122
            // (In order to validate the xml, 'strict' and 'wantXMLValidation' must be true).
123
            'wantXMLValidation' => true,
124
        ];
125
126
        return $conf;
127
    }
128
129
    private function getRequestedAuthnContext()
130
    {
131
        $security = $this->config()->get('Security');
132
133
        if (isset($security['requestedAuthnContext'])) {
134
            throw new Exception(sprintf(
135
                'Config setting "%s" is not settable directly. Please set either "%s" or "%s" in your YAML.',
136
                'SAMLConfiguration.Security.requestedAuthnContext',
137
                'SAMLConfiguration.Security.requestedAuthnContextBool',
138
                'SAMLConfiguration.Security.requestedAuthnContextArray'
139
            ));
140
        }
141
        if (isset($security['requestedAuthnContextBool']) && isset($security['requestedAuthnContextArray'])) {
142
            throw new Exception(sprintf(
143
                'Not permitted to set both "%s" and "%s" configuration elements. Check your config yamls.',
144
                'SAMLConfiguration.Security.requestedAuthnContextBool',
145
                'SAMLConfiguration.Security.requestedAuthnContextArray'
146
            ));
147
        }
148
149
        $requestedAuthnContext = [
150
            'urn:federation:authentication:windows',
151
            'urn:oasis:names:tc:SAML:2.0:ac:classes:Password',
152
            'urn:oasis:names:tc:SAML:2.0:ac:classes:X509',
153
        ];
154
155
        if (isset($security['requestedAuthnContextBool'])) {
156
            $requestedAuthnContext = $security['requestedAuthnContextBool'];
157
        }
158
159
        if (isset($security['requestedAuthnContextArray'])) {
160
            $requestedAuthnContext = $security['requestedAuthnContextArray'];
161
        }
162
163
        return $requestedAuthnContext;
164
    }
165
}
166