AuthController.php 5.4 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 43 44 45 46 47 48 49
    /**
     * Welcome
     *
     * This endpoint requires no auth and is the welcome page for any API user.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function welcome(): JsonResponse
    {
        return new JsonResponse(['welcome' => 'Welcome to the elock API.']);
    }

Jacob Priddy's avatar
Jacob Priddy committed
50
    /**
Jacob Priddy's avatar
Jacob Priddy committed
51 52 53 54 55 56 57 58 59 60
     * 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.
     *
     * @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
61 62 63 64
     * @param AuthenticateUseCase $authenticateUseCase
     * @return JsonResponse
     * @throws AuthenticationException
     * @throws EntityNotFoundException
Jacob Priddy's avatar
Jacob Priddy committed
65
     * @throws \Illuminate\Validation\ValidationException
Jacob Priddy's avatar
Jacob Priddy committed
66
     */
Jacob Priddy's avatar
Jacob Priddy committed
67 68
    public function login(AuthenticateUseCase $authenticateUseCase): JsonResponse
    {
Jacob Priddy's avatar
Jacob Priddy committed
69 70 71 72 73
        $this->validate($this->request, [
            'email' => 'required|string|email',
            'password' => 'required|string',
        ]);

74 75
        $presenter = new APIPresenter();

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

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

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

        return $redirector->to($authenticateUseCase->handToSaml());
105 106 107
    }

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

        try {
            $authenticateUseCase->handleSamlLogin($presenter);
        } catch (UserCreationException $e) {
125
            $this->setStatusCode(400);
126
            return $this->respondWithError(
127
                'Invalid SAML user given. If you believe this is in error, please contact an administrator.'
128 129 130
            );
        }

131 132 133 134 135 136
        return redirect()->intended(url(config('saml.home_page')))->withCookie(
            $this->cookieJar->make(
                'api_token',
                $presenter->getViewModel()['token']['value'],
                $presenter->getViewModel()['token']['minutes']
            )
Jacob Priddy's avatar
Jacob Priddy committed
137
        );
Jacob Priddy's avatar
Jacob Priddy committed
138
    }
139 140

    /**
Jacob Priddy's avatar
Jacob Priddy committed
141 142 143 144
     * Log out
     *
     * This endpoint logs out of saml and expires the associated api/login token and cookie.
     *
145 146 147
     * @param AuthenticateUseCase $authenticateUseCase
     * @return RedirectResponse
     */
Jacob Priddy's avatar
Jacob Priddy committed
148 149
    public function samlLogout(AuthenticateUseCase $authenticateUseCase): RedirectResponse
    {
150
        $this->cookieJar->queue($this->cookieJar->forget('api_token'));
151

152 153 154 155 156 157 158
        $logout = $authenticateUseCase->samlLogout($this->request->cookie('api_token'));

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

        return redirect($logout);
159
    }
Jacob Priddy's avatar
Jacob Priddy committed
160
}