Client   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 105
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 11
eloc 48
c 1
b 0
f 0
dl 0
loc 105
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A throwLoginError() 0 12 2
A __construct() 0 11 1
A login() 0 17 2
B sendRequest() 0 34 6
1
<?php
2
3
/**
4
 * FreeIPA library for PHP
5
 * Copyright (C) 2015-2019 Tobias Sette <[email protected]>
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Lesser General Public License as published by
9
 * the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public License
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
 */
20
declare(strict_types=1);
21
22
namespace Gnumoksha\FreeIpa\Infra\Rpc;
23
24
use Gnumoksha\FreeIpa\Infra\Json\Json;
25
use Gnumoksha\FreeIpa\Infra\Json\JsonException;
26
use Gnumoksha\FreeIpa\Infra\Rpc\Request\Body as RequestBodyInterface;
27
use Gnumoksha\FreeIpa\Infra\Rpc\Response\Body as ResponseBodyInterface;
28
use Gnumoksha\FreeIpa\Infra\Rpc\Response\BodyBuilder as ResponseBodyBuilder;
29
use Gnumoksha\FreeIpa\Options;
30
use Psr\Http\Client\ClientInterface;
31
use Psr\Http\Message\RequestFactoryInterface;
32
use Psr\Http\Message\ResponseInterface;
33
34
class Client
35
{
36
    /** @var \Gnumoksha\FreeIpa\Options */
37
    private $options;
38
    /** @var \Psr\Http\Client\ClientInterface */
39
    private $httpClient;
40
    /** @var \Psr\Http\Message\RequestFactoryInterface */
41
    private $requestFactory;
42
    /** @var \Gnumoksha\FreeIpa\Infra\Rpc\Response\BodyBuilder */
43
    private $responseBodyBuilder;
44
    /** @var bool */
45
    private $connected;
46
47
    public function __construct(
48
        Options $options,
49
        ClientInterface $httpClient,
50
        RequestFactoryInterface $requestFactory,
51
        ResponseBodyBuilder $responseBodyBuilder
52
    ) {
53
        $this->options             = $options;
54
        $this->httpClient          = $httpClient;
55
        $this->requestFactory      = $requestFactory;
56
        $this->responseBodyBuilder = $responseBodyBuilder;
57
        $this->connected           = false;
58
    }
59
60
    /**
61
     * Authenticate using an username and password.
62
     *
63
     * @see https://access.redhat.com/articles/2728021#end-point-pwd
64
     * @throws \Psr\Http\Client\ClientExceptionInterface
65
     */
66
    public function login(string $username, string $password): void
67
    {
68
        $request = $this->requestFactory->createRequest('POST', '/session/login_password')
69
                                        ->withAddedHeader('Content-Type', 'application/x-www-form-urlencoded')
70
                                        ->withAddedHeader('Accept', 'text/plain');
71
72
        $request->getBody()->write(http_build_query([
73
            'user'     => $username,
74
            'password' => $password,
75
        ]));
76
77
        $response = $this->httpClient->sendRequest($request);
78
        if ($response->getStatusCode() !== 200) {
79
            $this->throwLoginError($response);
80
        }
81
82
        $this->connected = true;
83
    }
84
85
    /**
86
     * @throws \Gnumoksha\FreeIpa\Infra\Json\JsonException
87
     * @throws \Psr\Http\Client\ClientExceptionInterface
88
     *
89
     * @see https://access.redhat.com/articles/2728021#end-points documentation
90
     */
91
    public function sendRequest(RequestBodyInterface $body): ResponseBodyInterface
92
    {
93
        if ($this->connected === false) {
94
            throw new ClientException('You are not authenticated.');
95
        }
96
97
        if ($this->options->getApiVersion() !== null) {
0 ignored issues
show
introduced by
The condition $this->options->getApiVersion() !== null is always true.
Loading history...
98
            $body = $body->withOption('version', $this->options->getApiVersion());
99
        }
100
101
        $request = $this->requestFactory->createRequest('POST', '/session/json')
102
                                        ->withAddedHeader('Content-Type', 'application/json')
103
                                        ->withAddedHeader('Accept', 'application/json');
104
105
        $request->getBody()
106
                ->write(Json::encode($body));
107
108
        $response = $this->httpClient->sendRequest($request);
109
        if ($response->getStatusCode() !== 200) {
110
            // #TODO better error message (i.e. auth fails)
111
            throw new ClientException(sprintf('Error: received HTTP status code "%s".', $response->getStatusCode()));
112
        }
113
114
        $responseBody = $this->responseBodyBuilder->build($response);
115
        if ($responseBody->hasError()) {
116
            try {
117
                $error = Json::encode($responseBody->getError());
118
            } catch (JsonException $e) {
119
                $error = 'The response\'s error field is an invalid json.';
120
            }
121
            throw new ClientException($error);
122
        }
123
124
        return $responseBody;
125
    }
126
127
    private function throwLoginError(ResponseInterface $response): void
128
    {
129
        $content = $response->getBody()->getContents();
130
        preg_match("/<title>(.*)<\/title>/siU", $content, $titleMatches);
131
132
        if (count($titleMatches) === 2) {
133
            $errorMessage = $titleMatches[1];
134
        } else {
135
            $errorMessage = 'Unknown login error.';
136
        }
137
138
        throw new ClientException($errorMessage, $response->getStatusCode());
139
    }
140
}
141