24
24
25
25
package org .hatdex .hat .api .controllers
26
26
27
- import java .net .{ URLDecoder , URLEncoder }
27
+ import java .net .{URLDecoder , URLEncoder }
28
28
29
29
import akka .Done
30
30
import javax .inject .Inject
31
31
import com .mohiva .play .silhouette .api .repositories .AuthInfoRepository
32
- import com .mohiva .play .silhouette .api .util .{ Credentials , PasswordHasherRegistry }
33
- import com .mohiva .play .silhouette .api .{ LoginEvent , Silhouette }
34
- import com .mohiva .play .silhouette .impl .exceptions .{ IdentityNotFoundException , InvalidPasswordException }
32
+ import com .mohiva .play .silhouette .api .util .{Credentials , PasswordHasherRegistry }
33
+ import com .mohiva .play .silhouette .api .{LoginEvent , Silhouette }
34
+ import com .mohiva .play .silhouette .impl .exceptions .{IdentityNotFoundException , InvalidPasswordException }
35
35
import com .mohiva .play .silhouette .impl .providers .CredentialsProvider
36
36
import org .hatdex .hat .api .json .HatJsonFormats
37
37
import org .hatdex .hat .api .models ._
38
38
import org .hatdex .hat .api .service .applications .ApplicationsService
39
- import org .hatdex .hat .api .service .{ HatServicesService , LogService , MailTokenService , UsersService }
39
+ import org .hatdex .hat .api .service .{HatServicesService , LogService , MailTokenService , UsersService }
40
40
import org .hatdex .hat .authentication ._
41
41
import org .hatdex .hat .phata .models ._
42
- import org .hatdex .hat .resourceManagement .{ HatServerProvider , _ }
43
- import org .hatdex .hat .utils .{ HatBodyParsers , HatMailer }
44
- import play .api .Logger
45
- import play .api .cache .{ Cached , CachedBuilder }
42
+ import org .hatdex .hat .resourceManagement .{HatServerProvider , _ }
43
+ import org .hatdex .hat .utils .{HatBodyParsers , HatMailer }
44
+ import play .api .{ Configuration , Logger }
45
+ import play .api .cache .{Cached , CachedBuilder }
46
46
import play .api .libs .json .Json
47
- import play .api .mvc .{ Action , _ }
47
+ import play .api .libs .ws .WSClient
48
+ import play .api .mvc .{Action , _ }
48
49
49
50
import scala .concurrent .ExecutionContext .Implicits .global
50
51
import scala .concurrent .Future
51
52
52
53
class Authentication @ Inject () (
53
54
components : ControllerComponents ,
54
55
cached : Cached ,
56
+ configuration : Configuration ,
55
57
parsers : HatBodyParsers ,
56
58
hatServerProvider : HatServerProvider ,
57
59
silhouette : Silhouette [HatApiAuthEnvironment ],
@@ -64,6 +66,7 @@ class Authentication @Inject() (
64
66
logService : LogService ,
65
67
mailer : HatMailer ,
66
68
tokenService : MailTokenService [MailTokenUser ],
69
+ wsClient : WSClient ,
67
70
limiter : UserLimiter ) extends HatApiController (components, silhouette) with HatJsonFormats {
68
71
69
72
private val logger = Logger (this .getClass)
@@ -228,15 +231,10 @@ class Authentication @Inject() (
228
231
}
229
232
}
230
233
231
- /*
232
- BEGIN: hat-claim
233
- Entire Section below is on HAT Claim.
234
- TODO: Refactor to New File?
235
- */
236
234
/**
237
235
* Sends an email to the owner with a link to claim the hat
238
236
*/
239
- def claim (): Action [ApiClaimHatRequest ] = UserAwareAction .async(parsers.json[ApiClaimHatRequest ]) { implicit request =>
237
+ def handleClaimStart (): Action [ApiClaimHatRequest ] = UserAwareAction .async(parsers.json[ApiClaimHatRequest ]) { implicit request =>
240
238
241
239
val claimHatRequest = request.body
242
240
val email = request.dynamicEnvironment.ownerEmail
@@ -301,7 +299,67 @@ class Authentication @Inject() (
301
299
Future .successful(response)
302
300
}
303
301
}
304
- /*
305
- END: hat-claim
306
- */
302
+
303
+ def handleClaimComplete (claimToken : String ): Action [HatClaimCompleteRequest ] = UserAwareAction .async(parsers.json[HatClaimCompleteRequest ]) { implicit request =>
304
+ implicit val hatClaimComplete : HatClaimCompleteRequest = request.body
305
+
306
+ tokenService.retrieve(claimToken).flatMap {
307
+ case Some (token) if token.isSignUp && ! token.isExpired && token.email == request.dynamicEnvironment.ownerEmail =>
308
+ usersService.listUsers.map(_.find(_.roles.contains(Owner ()))).flatMap {
309
+ case Some (user) =>
310
+ val eventualResult = for {
311
+ _ <- updateHatMembership(hatClaimComplete)
312
+ _ <- authInfoRepository.update(user.loginInfo, passwordHasherRegistry.current.hash(request.body.password))
313
+ _ <- tokenService.expire(token.id)
314
+ authenticator <- env.authenticatorService.create(user.loginInfo)
315
+ result <- env.authenticatorService.renew(authenticator, Ok (Json .toJson(SuccessResponse (" HAT claimed" ))))
316
+ _ <- logService.logAction(request.dynamicEnvironment.domain, LogRequest (" claimed" , None , None ), None ).recover {
317
+ case e =>
318
+ logger.error(s " LogActionError::unclaimed. Reason: ${e.getMessage}" )
319
+ Done
320
+ }
321
+ } yield {
322
+ // env.eventBus.publish(LoginEvent(user, request))
323
+ // mailer.passwordChanged(token.email, user)
324
+
325
+ result
326
+ }
327
+
328
+ eventualResult.recover {
329
+ case e =>
330
+ logger.error(s " HAT claim process failed with error ${e.getMessage}" )
331
+ BadRequest (Json .toJson(ErrorMessage (" Bad Request" , " HAT claim process failed" )))
332
+ }
333
+
334
+ case None => Future .successful(Unauthorized (Json .toJson(ErrorMessage (" HAT claim unauthorized" , " No user matching token" ))))
335
+ }
336
+
337
+ case Some (_) =>
338
+ Future .successful(Unauthorized (Json .toJson(ErrorMessage (" Invalid Token" , " Token expired or invalid" ))))
339
+
340
+ case None =>
341
+ Future .successful(Unauthorized (Json .toJson(ErrorMessage (" Invalid Token" , " Token does not exist" ))))
342
+ }
343
+ }
344
+
345
+ private def updateHatMembership (claim : HatClaimCompleteRequest ): Future [Done ] = {
346
+ val path = " api/products/hat/claim"
347
+ val hattersUrl = s " ${configuration.underlying.getString(" hatters.scheme" )}${configuration.underlying.getString(" hatters.address" )}"
348
+
349
+ logger.info(s " Proxy POST request to $hattersUrl/ $path with parameters: $claim" )
350
+
351
+ val futureResponse = wsClient.url(s " $hattersUrl/ $path" )
352
+ // .withHttpHeaders("x-auth-token" → token.accessToken)
353
+ .post(Json .toJson(claim.copy(password = " " )))
354
+
355
+ futureResponse.flatMap { response =>
356
+ response.status match {
357
+ case OK =>
358
+ Future .successful(Done )
359
+ case _ =>
360
+ logger.error(s " Failed to claim HAT with Hatters. Claim details: \n $claim\n Hatters response: ${response.body}" )
361
+ Future .failed(new UnknownError (" HAT claim failed" ))
362
+ }
363
+ }
364
+ }
307
365
}
0 commit comments