UNPKG

5.17 kBJavaScriptView Raw
1'use strict'
2
3const debug = require('./../debug').authentication
4
5const AuthRequest = require('./auth-request')
6const { PasswordAuthenticator, TlsAuthenticator } = require('../models/authenticator')
7
8const PASSWORD_AUTH = 'password'
9const TLS_AUTH = 'tls'
10
11/**
12 * Models a local Login request
13 */
14class LoginRequest extends AuthRequest {
15 /**
16 * @constructor
17 * @param options {Object}
18 *
19 * @param [options.response] {ServerResponse} middleware `res` object
20 * @param [options.session] {Session} req.session
21 * @param [options.userStore] {UserStore}
22 * @param [options.accountManager] {AccountManager}
23 * @param [options.returnToUrl] {string}
24 * @param [options.authQueryParams] {Object} Key/value hashmap of parsed query
25 * parameters that will be passed through to the /authorize endpoint.
26 * @param [options.authenticator] {Authenticator} Auth strategy by which to
27 * log in
28 */
29 constructor (options) {
30 super(options)
31
32 this.authenticator = options.authenticator
33 this.authMethod = options.authMethod
34 }
35
36 /**
37 * Factory method, returns an initialized instance of LoginRequest
38 * from an incoming http request.
39 *
40 * @param req {IncomingRequest}
41 * @param res {ServerResponse}
42 * @param authMethod {string}
43 *
44 * @return {LoginRequest}
45 */
46 static fromParams (req, res, authMethod) {
47 let options = AuthRequest.requestOptions(req, res)
48 options.authMethod = authMethod
49
50 switch (authMethod) {
51 case PASSWORD_AUTH:
52 options.authenticator = PasswordAuthenticator.fromParams(req, options)
53 break
54
55 case TLS_AUTH:
56 options.authenticator = TlsAuthenticator.fromParams(req, options)
57 break
58
59 default:
60 options.authenticator = null
61 break
62 }
63
64 return new LoginRequest(options)
65 }
66
67 /**
68 * Handles a Login GET request on behalf of a middleware handler, displays
69 * the Login page.
70 * Usage:
71 *
72 * ```
73 * app.get('/login', LoginRequest.get)
74 * ```
75 *
76 * @param req {IncomingRequest}
77 * @param res {ServerResponse}
78 */
79 static get (req, res) {
80 const request = LoginRequest.fromParams(req, res)
81
82 request.renderForm(null, req)
83 }
84
85 /**
86 * Handles a Login via Username+Password.
87 * Errors encountered are displayed on the Login form.
88 * Usage:
89 *
90 * ```
91 * app.post('/login/password', LoginRequest.loginPassword)
92 * ```
93 *
94 * @param req
95 * @param res
96 *
97 * @return {Promise}
98 */
99 static loginPassword (req, res) {
100 debug('Logging in via username + password')
101
102 let request = LoginRequest.fromParams(req, res, PASSWORD_AUTH)
103
104 return LoginRequest.login(request)
105 }
106
107 /**
108 * Handles a Login via WebID-TLS.
109 * Errors encountered are displayed on the Login form.
110 * Usage:
111 *
112 * ```
113 * app.post('/login/tls', LoginRequest.loginTls)
114 * ```
115 *
116 * @param req
117 * @param res
118 *
119 * @return {Promise}
120 */
121 static loginTls (req, res) {
122 debug('Logging in via WebID-TLS certificate')
123
124 let request = LoginRequest.fromParams(req, res, TLS_AUTH)
125
126 return LoginRequest.login(request)
127 }
128
129 /**
130 * Performs the login operation -- loads and validates the
131 * appropriate user, inits the session with credentials, and redirects the
132 * user to continue their auth flow.
133 *
134 * @param request {LoginRequest}
135 *
136 * @return {Promise}
137 */
138 static login (request) {
139 return request.authenticator.findValidUser()
140
141 .then(validUser => {
142 request.initUserSession(validUser)
143
144 request.redirectPostLogin(validUser)
145 })
146
147 .catch(error => request.error(error))
148 }
149
150 /**
151 * Returns a URL to redirect the user to after login.
152 * Either uses the provided `redirect_uri` auth query param, or simply
153 * returns the user profile URI if none was provided.
154 *
155 * @param validUser {UserAccount}
156 *
157 * @return {string}
158 */
159 postLoginUrl (validUser) {
160 // Login request is part of an app's auth flow
161 if (/token|code/.test(this.authQueryParams['response_type'])) {
162 return this.sharingUrl()
163 // Login request is a user going to /login in browser
164 } else if (validUser) {
165 return this.authQueryParams['redirect_uri'] || validUser.accountUri
166 }
167 }
168
169 /**
170 * Redirects the Login request to continue on the OIDC auth workflow.
171 */
172 redirectPostLogin (validUser) {
173 let uri = this.postLoginUrl(validUser)
174 debug('Login successful, redirecting to ', uri)
175 this.response.redirect(uri)
176 }
177
178 /**
179 * Renders the login form
180 */
181 renderForm (error, req) {
182 let queryString = req && req.url && req.url.replace(/[^?]+\?/, '') || ''
183 let params = Object.assign({}, this.authQueryParams,
184 {
185 registerUrl: this.registerUrl(),
186 returnToUrl: this.returnToUrl,
187 enablePassword: this.localAuth.password,
188 enableTls: this.localAuth.tls,
189 tlsUrl: `/login/tls?${encodeURIComponent(queryString)}`
190 })
191
192 if (error) {
193 params.error = error.message
194 this.response.status(error.statusCode)
195 }
196 this.response.render('auth/login', params)
197 }
198}
199
200module.exports = {
201 LoginRequest,
202 PASSWORD_AUTH,
203 TLS_AUTH
204}