SAMLConfiguration::asArray()   B
last analyzed

Complexity

Conditions 8
Paths 96

Size

Total Lines 114
Code Lines 59

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 8
eloc 59
c 3
b 0
f 0
nc 96
nop 0
dl 0
loc 114
rs 7.6501

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 SilverStripe\SAML\Services;
4
5
use OneLogin\Saml2\Constants;
6
use SilverStripe\Core\Injector\Injectable;
7
use SilverStripe\Core\Config\Configurable;
8
use SilverStripe\Control\Director;
9
use SilverStripe\Core\Injector\Injector;
10
11
/**
12
 * Class SAMLConfiguration
13
 *
14
 * This object's job is to convert configuration from SilverStripe config system
15
 * into an array that can be consumed by the Onelogin SAML implementation.
16
 *
17
 * The configuration tells the IdP and SP how to establish the circle of trust - i.e.
18
 * how to exchange certificates and which endpoints to use (e.g. see SAMLConfiguration::metadata).
19
 *
20
 * https://syncplicity.zendesk.com/hc/en-us/articles/202392814-Single-sign-on-with-ADFS
21
 *
22
 * @package activedirectory
23
 */
24
class SAMLConfiguration
25
{
26
    use Injectable;
27
    use Configurable;
28
29
    /**
30
     * @var bool
31
     */
32
    private static $strict;
0 ignored issues
show
introduced by
The private property $strict is not used, and could be removed.
Loading history...
33
34
    /**
35
     * @var bool
36
     */
37
    private static $debug;
0 ignored issues
show
introduced by
The private property $debug is not used, and could be removed.
Loading history...
38
39
    /**
40
     * @var array
41
     */
42
    private static $SP;
0 ignored issues
show
introduced by
The private property $SP is not used, and could be removed.
Loading history...
43
44
    /**
45
     * @var array
46
     */
47
    private static $IdP;
0 ignored issues
show
introduced by
The private property $IdP is not used, and could be removed.
Loading history...
48
49
    /**
50
     * @var array List of valid AuthN contexts that the IdP can use to authenticate a user. Will be passed to the IdP in
51
     * every AuthN request (e.g. every login attempt made by a user). The default values should work for ADFS 2.0, but
52
     * can be overridden if needed.
53
     */
54
    private static $authn_contexts;
0 ignored issues
show
introduced by
The private property $authn_contexts is not used, and could be removed.
Loading history...
55
56
    /**
57
     * @config
58
     * @var bool Whether or not we expect to receive a binary NameID from the IdP. We expect to receive a binary NameID
59
     * from ADFS, but don't expect it from Azure AD or most other SAML implementations that provide GUIDs.
60
     *
61
     * Defaults to true to preserve backwards compatibility (ADFS).
62
     */
63
    private static $expect_binary_nameid = true;
0 ignored issues
show
introduced by
The private property $expect_binary_nameid is not used, and could be removed.
Loading history...
64
65
    /**
66
     * @config
67
     * @var bool Whether or not we allow searching for existing members in the SilverStripe database based on their
68
     * email address. Marked as insecure because if warnings in developer documentation are not read and understood,
69
     * this can provide access to the website to people who should not otherwise have access.
70
     *
71
     * Defaults to false to prevent looking up members based on email address.
72
     */
73
    private static $allow_insecure_email_linking = false;
0 ignored issues
show
introduced by
The private property $allow_insecure_email_linking is not used, and could be removed.
Loading history...
74
75
    /**
76
     * @config
77
     * @var bool Decide if GUID should be exposed as an attribute mappable using `GUID` as the claim. This is a feature
78
     * that is found in other SAML libraries but in an ideal world should not be utilised in favour of the IdP offering
79
     * the nameid data as another "more stable" attribute.
80
     * 
81
     * Note that this data will be effected by:
82
     *  - The expect_binary_nameid configuration value
83
     *  - The extension point `updateGuid` on SAMLController
84
     */
85
    private static $expose_guid_as_attribute = false;
0 ignored issues
show
introduced by
The private property $expose_guid_as_attribute is not used, and could be removed.
Loading history...
86
87
    /**
88
     * @config
89
     * @example ['GET Query Parameter Name' => 'Parameter Value', ... ]
90
     *
91
     * @var string[]
92
     */
93
    private static $additional_get_query_params = [];
0 ignored issues
show
introduced by
The private property $additional_get_query_params is not used, and could be removed.
Loading history...
94
95
    /**
96
     * @return array
97
     */
98
    public function asArray()
99
    {
100
        $conf = [];
101
102
        $conf['strict'] = $this->config()->get('strict');
103
        $conf['debug'] = $this->config()->get('debug');
104
105
        // SERVICE PROVIDER SECTION
106
        $sp = $this->config()->get('SP');
107
108
        $spX509Cert = Injector::inst()->convertServiceProperty($sp['x509cert']);
109
        $spCertPath = Director::is_absolute($spX509Cert)
0 ignored issues
show
Bug introduced by
It seems like $spX509Cert can also be of type array; however, parameter $path of SilverStripe\Control\Director::is_absolute() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

109
        $spCertPath = Director::is_absolute(/** @scrutinizer ignore-type */ $spX509Cert)
Loading history...
110
            ? $spX509Cert
111
            : sprintf('%s/%s', BASE_PATH, $spX509Cert);
0 ignored issues
show
Bug introduced by
It seems like $spX509Cert can also be of type array; however, parameter $values of sprintf() does only seem to accept double|integer|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

111
            : sprintf('%s/%s', BASE_PATH, /** @scrutinizer ignore-type */ $spX509Cert);
Loading history...
112
        $spPrivateKey = Injector::inst()->convertServiceProperty($sp['privateKey']);
113
        $spKeyPath = Director::is_absolute($spPrivateKey)
114
            ? $spPrivateKey
115
            : sprintf('%s/%s', BASE_PATH, $spPrivateKey);
116
117
        $conf['sp']['entityId'] = Injector::inst()->convertServiceProperty($sp['entityId']);
118
        $conf['sp']['assertionConsumerService'] = [
119
            'url' => Injector::inst()->convertServiceProperty($sp['entityId']) . '/saml/acs',
120
            'binding' => Constants::BINDING_HTTP_POST
121
        ];
122
        $conf['sp']['NameIDFormat'] = isset($sp['nameIdFormat']) ?
123
            $sp['nameIdFormat'] : Constants::NAMEID_TRANSIENT;
124
        $conf['sp']['x509cert'] = file_get_contents($spCertPath);
0 ignored issues
show
Bug introduced by
It seems like $spCertPath can also be of type array; however, parameter $filename of file_get_contents() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

124
        $conf['sp']['x509cert'] = file_get_contents(/** @scrutinizer ignore-type */ $spCertPath);
Loading history...
125
        $conf['sp']['privateKey'] = file_get_contents($spKeyPath);
126
127
        // IDENTITY PROVIDER SECTION
128
        $idp = $this->config()->get('IdP');
129
        $conf['idp']['entityId'] = Injector::inst()->convertServiceProperty($idp['entityId']);
130
        $conf['idp']['singleSignOnService'] = [
131
            'url' => Injector::inst()->convertServiceProperty($idp['singleSignOnService']),
132
            'binding' => Constants::BINDING_HTTP_REDIRECT,
133
        ];
134
        if (isset($idp['singleLogoutService'])) {
135
            $conf['idp']['singleLogoutService'] = [
136
                'url' => Injector::inst()->convertServiceProperty($idp['singleLogoutService']),
137
                'binding' => Constants::BINDING_HTTP_REDIRECT,
138
            ];
139
        }
140
141
        $idpX509Cert = Injector::inst()->convertServiceProperty($idp['x509cert']);
142
        $idpCertPath = Director::is_absolute($idpX509Cert)
143
            ? $idpX509Cert
144
            : sprintf('%s/%s', BASE_PATH, $idpX509Cert);
145
        $conf['idp']['x509cert'] = file_get_contents($idpCertPath);
146
147
        // SECURITY SECTION
148
        $security = $this->config()->get('Security');
149
        $signatureAlgorithm = $security['signatureAlgorithm'];
150
151
        $authnContexts = $this->config()->get('authn_contexts');
152
        $disableAuthnContexts = $this->config()->get('disable_authn_contexts');
153
154
        if ((bool)$disableAuthnContexts) {
155
            $authnContexts = false;
156
        } else {
157
            if (!is_array($authnContexts)) {
158
                // Fallback to default contexts if the supplied value isn't valid
159
                $authnContexts = [
160
                    'urn:federation:authentication:windows',
161
                    'urn:oasis:names:tc:SAML:2.0:ac:classes:Password',
162
                    'urn:oasis:names:tc:SAML:2.0:ac:classes:X509',
163
                ];
164
            }
165
        }
166
167
        $conf['security'] = [
168
            /** signatures and encryptions offered */
169
            // Indicates that the nameID of the <samlp:logoutRequest> sent by this SP will be encrypted.
170
            'nameIdEncrypted' => true,
171
            // Indicates whether the <samlp:AuthnRequest> messages sent by this SP will be signed. [Metadata of the
172
            // SP will offer this info]
173
            'authnRequestsSigned' => true,
174
            // Indicates whether the <samlp:logoutRequest> messages sent by this SP will be signed.
175
            'logoutRequestSigned' => true,
176
            // Indicates whether the <samlp:logoutResponse> messages sent by this SP will be signed.
177
            'logoutResponseSigned' => true,
178
            'signMetadata' => false,
179
            /** signatures and encryptions required **/
180
            // Indicates a requirement for the <samlp:Response>, <samlp:LogoutRequest>
181
            // and <samlp:LogoutResponse> elements received by this SP to be signed.
182
            'wantMessagesSigned' => false,
183
            // Indicates a requirement for the <saml:Assertion> elements received by
184
            // this SP to be signed. [Metadata of the SP will offer this info]
185
            'wantAssertionsSigned' => true,
186
            // Indicates a requirement for the NameID received by
187
            // this SP to be encrypted.
188
            'wantNameIdEncrypted' => false,
189
190
            // Algorithm that the toolkit will use on signing process. Options:
191
            //  - 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
192
            //  - 'http://www.w3.org/2000/09/xmldsig#dsa-sha1'
193
            //  - 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'
194
            //  - 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'
195
            //  - 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512'
196
            'signatureAlgorithm' => $signatureAlgorithm,
197
198
            // Authentication context.
199
            // Set to false and no AuthContext will be sent in the AuthNRequest,
200
            // Set true or don't present thi parameter and you will get an AuthContext
201
            // 'exact' 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'
202
            // Set an array with the possible auth context values:
203
            // array ('urn:oasis:names:tc:SAML:2.0:ac:classes:Password', 'urn:oasis:names:tc:SAML:2.0:ac:classes:X509'),
204
            'requestedAuthnContext' => $authnContexts,
205
206
            // Indicates if the SP will validate all received xmls.
207
            // (In order to validate the xml, 'strict' and 'wantXMLValidation' must be true).
208
            'wantXMLValidation' => true,
209
        ];
210
211
        return $conf;
212
    }
213
}
214