AuthController.php 5.82 KB
Newer Older
Jacob Priddy's avatar
Jacob Priddy committed
1 2
<?php

3
namespace App\Http\Controllers\Api;
Jacob Priddy's avatar
Jacob Priddy committed
4 5

use Illuminate\Http\Request;
6
use Illuminate\Cookie\CookieJar;
Jacob Priddy's avatar
Jacob Priddy committed
7
use Illuminate\Http\JsonResponse;
8
use Illuminate\Routing\Redirector;
9
use Source\Authorization\Authorizer;
10
use Illuminate\Http\RedirectResponse;
11
use Source\Exceptions\AuthenticationException;
Jacob Priddy's avatar
Jacob Priddy committed
12 13 14
use Source\Exceptions\EntityNotFoundException;
use Source\UseCases\Users\Authenticate\APIPresenter;
use Source\UseCases\Users\Authenticate\AuthenticateUseCase;
15
use Source\UseCases\Users\Authenticate\UserCreationException;
Jacob Priddy's avatar
Jacob Priddy committed
16

Jacob Priddy's avatar
Jacob Priddy committed
17 18 19 20 21
/**
 * @group Authentication
 *
 * This set of routes deals with authentication with the application through SAML and application login.
 */
Jacob Priddy's avatar
Jacob Priddy committed
22 23
class AuthController extends ApiController
{
24 25
    protected CookieJar $cookieJar;

26 27 28 29 30 31
    /**
     * @param \Illuminate\Http\Request         $request
     * @param \Source\Authorization\Authorizer $authorizer
     * @param \Illuminate\Cookie\CookieJar     $cookieJar
     */
    public function __construct(Request $request, Authorizer $authorizer, CookieJar $cookieJar)
Jacob Priddy's avatar
Jacob Priddy committed
32
    {
33 34
        parent::__construct($request, $authorizer);

35
        $this->cookieJar = $cookieJar;
Jacob Priddy's avatar
Jacob Priddy committed
36 37
    }

Jacob Priddy's avatar
Jacob Priddy committed
38 39 40 41 42
    /**
     * Welcome
     *
     * This endpoint requires no auth and is the welcome page for any API user.
     *
Jacob Priddy's avatar
Jacob Priddy committed
43 44
     * @unauthenticated
     *
Jacob Priddy's avatar
Jacob Priddy committed
45 46 47 48 49 50 51
     * @return \Illuminate\Http\JsonResponse
     */
    public function welcome(): JsonResponse
    {
        return new JsonResponse(['welcome' => 'Welcome to the elock API.']);
    }

Jacob Priddy's avatar
Jacob Priddy committed
52
    /**
Jacob Priddy's avatar
Jacob Priddy committed
53 54 55 56 57
     * Login request to application
     *
     * This endpoint returns a token that can be used in other endpoints as well as setting a cookie.
     * One does not need to make a request to this if they have a valid token.
     *
Jacob Priddy's avatar
Jacob Priddy committed
58
     * @unauthenticated
Jacob Priddy's avatar
Jacob Priddy committed
59 60 61 62 63
     * @bodyParam email string required The email of the login user. Example: sithL0rd@senate.com
     * @bodyParam password string required The password of the user to login as. Example: I am the senate
     *
     * @response 422 {"message":"The given data was invalid.","errors":{"email":["The email field is required."],"password":["The password field is required."]}}
     *
Jacob Priddy's avatar
Jacob Priddy committed
64 65 66 67
     * @param AuthenticateUseCase $authenticateUseCase
     * @return JsonResponse
     * @throws AuthenticationException
     * @throws EntityNotFoundException
Jacob Priddy's avatar
Jacob Priddy committed
68
     * @throws \Illuminate\Validation\ValidationException
Jacob Priddy's avatar
Jacob Priddy committed
69
     */
Jacob Priddy's avatar
Jacob Priddy committed
70 71
    public function login(AuthenticateUseCase $authenticateUseCase): JsonResponse
    {
Jacob Priddy's avatar
Jacob Priddy committed
72 73 74 75 76
        $this->validate($this->request, [
            'email' => 'required|string|email',
            'password' => 'required|string',
        ]);

77 78
        $presenter = new APIPresenter();

79
        $authenticateUseCase->attempt($presenter, $this->request->all());
Jacob Priddy's avatar
Jacob Priddy committed
80

81
        return $this->respondWithData($presenter->getViewModel())->withCookie(
82
            $this->cookieJar->make(
83 84 85 86 87 88 89
                'api_token',
                $presenter->getViewModel()['token']['value'],
                $presenter->getViewModel()['token']['minutes']
            )
        );
    }

90
    /**
Jacob Priddy's avatar
Jacob Priddy committed
91 92 93 94
     * Start a saml login request
     *
     * This route redirects the user to the running SAML authentication instance to start authentication with SAML
     *
Jacob Priddy's avatar
Jacob Priddy committed
95
     * @unauthenticated
96 97 98
     * @urlParam intended The url to redirect back to once authentication is successful.
     *
     * @param \Illuminate\Routing\Redirector                          $redirector
99 100 101
     * @param \Source\UseCases\Users\Authenticate\AuthenticateUseCase $authenticateUseCase
     * @return \Illuminate\Http\RedirectResponse
     */
102
    public function samlLogin(Redirector $redirector, AuthenticateUseCase $authenticateUseCase): RedirectResponse
Jacob Priddy's avatar
Jacob Priddy committed
103
    {
104 105 106 107 108
        if ($this->request->has('intended')) {
            $redirector->setIntendedUrl($this->request->input('intended'));
        }

        return $redirector->to($authenticateUseCase->handToSaml());
109 110 111
    }

    /**
Jacob Priddy's avatar
Jacob Priddy committed
112 113
     * Handle SAML login
     *
114
     * This API is only meant to be used by SAML after a return from a login.
Jacob Priddy's avatar
Jacob Priddy committed
115
     *
Jacob Priddy's avatar
Jacob Priddy committed
116 117
     * @unauthenticated
     *
118 119 120
     * @param AuthenticateUseCase $authenticateUseCase
     * @return mixed
     * @throws EntityNotFoundException
Jacob Priddy's avatar
Jacob Priddy committed
121
     * @throws \Source\Exceptions\EntityExistsException
122
     * @throws \Source\Exceptions\AuthorizationException
123
     */
Jacob Priddy's avatar
Jacob Priddy committed
124 125
    public function handle(AuthenticateUseCase $authenticateUseCase)
    {
126 127 128 129 130
        $presenter = new APIPresenter();

        try {
            $authenticateUseCase->handleSamlLogin($presenter);
        } catch (UserCreationException $e) {
131
            $this->setStatusCode(400);
132
            return $this->respondWithError(
133
                'Invalid SAML user given. If you believe this is in error, please contact an administrator.'
134 135 136
            );
        }

137 138 139 140 141 142 143 144 145 146
        $response = redirect();

        if ($presenter->isNewUser()) {
            $response = $response->route('web.doorcode')
                ->with('message', 'I see you are a new user! Please set your doorcode for door access.');
        } else {
            $response = $response->intended(url(config('saml.home_page')));
        }

        return $response->withCookie(
147 148 149 150 151
            $this->cookieJar->make(
                'api_token',
                $presenter->getViewModel()['token']['value'],
                $presenter->getViewModel()['token']['minutes']
            )
Jacob Priddy's avatar
Jacob Priddy committed
152
        );
Jacob Priddy's avatar
Jacob Priddy committed
153
    }
154 155

    /**
Jacob Priddy's avatar
Jacob Priddy committed
156 157 158 159
     * Log out
     *
     * This endpoint logs out of saml and expires the associated api/login token and cookie.
     *
Jacob Priddy's avatar
Jacob Priddy committed
160 161
     * @unauthenticated
     *
162 163 164
     * @param AuthenticateUseCase $authenticateUseCase
     * @return RedirectResponse
     */
Jacob Priddy's avatar
Jacob Priddy committed
165 166
    public function samlLogout(AuthenticateUseCase $authenticateUseCase): RedirectResponse
    {
167
        $this->cookieJar->queue($this->cookieJar->forget('api_token'));
168

169 170 171 172 173 174 175
        $logout = $authenticateUseCase->samlLogout($this->request->cookie('api_token'));

        if ($this->request->has('intended')) {
            $logout = $this->request->input('intended');
        }

        return redirect($logout);
176
    }
Jacob Priddy's avatar
Jacob Priddy committed
177
}