SAMLConfiguration::asArray()   C
last analyzed

Complexity

Conditions 8
Paths 128

Size

Total Lines 93

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 93
rs 6.7216
c 0
b 0
f 0
cc 8
nc 128
nop 0

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