Logging user activity in another logical layer without global HttpContext - scala

I'm looking for a good solution to log DB changes in a web application developed using Play/Scala/ReactiveMongo. I need to know who changed what.
I have a separate layer namely Services in which all data access and business logics happens. All saves/updates/removes are done by certain methods so I can log them safely in just 3 or 4 methods but I need user identity there.
I don't have access to current user in services! There is no global HttpContext or Request or something like that which let me get the user identity (I think this way of getting user identity was incorrect of course).
I have a solution:
Add an implicit parameter to all methods of services which have side effects (change DB) and pass user identity to them.
def save(model: A)(implicit userIdentity: Option[UserIndentity] = None) = { ... }
As I wrapped default request, it can extend UserIdentity trait so that the implicit request matches the implicit parameters.
class MyRequest[A](...) extends WrappedRequest[A](request) extends UserIdentity
Finally, actions can use services like this:
def index() = MyAction { implicit request =>
//...
defaultService.save(model)
//...
}
The bad thing is that I have to add implicit parameters to those service methods. Isn't there another solution to get current user without polluting method signatures.

What's the problem with simply adding UserIdentity as an argument to your functions? Knowing who the user is seems to be important for your business logic - after all, today you want to log who performed the operation, tomorrow you will want to make sure this particular user is allowed to do it.
And I would just use a real UserIdentity object, not some hack with WrappedRequest, your services don't need to mess with a WrappedRequest instance.

Related

Is there any way to access arguments of handler method in a NestJS guard?

I want to implement a smart guard in NestJS which can protect method execution based on decisions declared in a special method annotation.
For example the use-case is:
normal users can change only their own user information
Admin can change any user information
I want to specify decisions by declarative way: using annotations. I've almost completed the implementation, this requirement can be declared this way:
#Put('user')
#UseGuards(HttpBasicAuthGuard, DecisionGuard)
#DecisionExpr(new Decisions(Op.OR, [
new RootDecision(Role.ADMIN),
new CurrentUserDecision({ sourceParamId: 'user', func: (user: User) => user.id}),
]))
updateUser(#ParamId('user') #Body() u: User, #ParamId('etc') etc): any {
// call user service and update user in model
}
Declared decisions are stored into metadata of handler method by
'#DecisionExpr'.
Parameter indexes are collected by '#ParamId' and also stored into
metadata of handler method.
Decisions are evaluated by DecisionGuard which can access current
user and authorities from Request (via ExecutionContext), it can also
access easily decisions and identified parameter indexes from
metadata.
The only problem how can I access arguments of handler method from DecisionGuard. Arguments of handler method contain data which can be compared to the current user and make a decision for DecisionGuard.
Is it possible, at all?
The only way I found was to implement a method decorator and call a custom method by changing PropertyDescriptor.value (3rd argument of method decorator):
export const DecisionExpr = (data: Decision): MethodDecorator => {
...
const childFunction = descriptor.value;
descriptor.value = (...args: any[]) => {
console.log('DecisionExpr child function - args:', args);
// call original method
return childFunction.apply(this, args);
};
}
But the problem with this solution is that a custom method is only called AFTER guards.
My last chance is moving this protection from DecisionGuard into the custom method of DecisionExpr method decorator - but I don't like it. I don't want to introduce a new pattern for method protection.
Maybe I will try this solution to fulfill my requirements:
https://docs.nestjs.com/security/authorization#integrating-casl

How to properly pass many dependencies (external APIs) to a class in Scala?

How to properly pass many dependencies (external APIs) to a class in Scala?
I'm working on the application that uses many APIs to collect data. For API's I have trait like below.
trait api {
def url: Foo
def parse: Bar
}
Also, there are about 10 implementations of the api trait (one for each API). Inside a parent actor, I want to create a child actor for every external API. I created new trait and implementation,
trait ExternalApis {
val apiList: List[api]
}
object MyApis extends ExternalApis {
val apiList = List(new ApiImpl1, ..., new ApiImpl10)
}
so now I can pass MyApis object (or any other implementation of ExternalApis) to parent actor and map over apiList for creating such child actors.
It seems to me I'm missing something. Are there more proper ways to do it?
The implementation that you have made looks nearly ready. Just something I would like to add are:
Passing an API List may not be the most ideal way to do such a thing. Anytime you would like to add/remove something to the API list, you would have to change different areas of the code. A suggestion would be to read this from a config folder, where the config folders would contain things such as url, username, password etc.
If you could provide more insight on the usage of these API's, it would help my answer a lot.
Hope this helped!

How can I perform session based logging in Play Framework

We are currently using the Play Framework and we are using the standard logging mechanism. We have implemented a implicit context to support passing username and session id to all service methods. We want to implement logging so that it is session based. This requires implementing our own logger. This works for our own logs but how do we do the same for basic exception handling and logs as a result. Maybe there is a better way to capture this then with implicits or how can we override the exception handling logging. Essentially, we want to get as many log messages to be associated to the session.
It depends if you are doing reactive style development or standard synchronous development:
If standard synchronous development (i.e. no futures, 1 thread per request) - then I'd recommend you just use MDC, which adds values onto Threadlocal for logging. You can then customise the output in logback / log4j. When you get the username / session (possibly in a Filter or in your controller), you can then set the values there and then and you do not need to pass them around with implicits.
If you are doing reactive development you have a couple options:
You can still use MDC, except you'd have to use a custom Execution Context that effectively copies the MDC values to the thread, since each request could in theory be handled by multiple threads. (as described here: http://code.hootsuite.com/logging-contextual-info-in-an-asynchronous-scala-application/)
The alternative is the solution which I tend to use (and close to what you have now): You could make a class which represents MyAppRequest. Set the username, session info, and anything else, on that. You can continue to pass it around as an implicit. However, instead of using Action.async, you make your own MyAction class which an be used like below
myAction.async { implicit myRequest => //some code }
Inside the myAction, you'd have to catch all Exceptions and deal with future failures, and do the error handling manually instead of relying on the ErrorHandler. I often inject myAction into my Controllers and put common filter functionality in it.
The down side of this is, it is just a manual method. Also I've made MyAppRequest hold a Map of loggable values which can be set anywhere, which means it had to be a mutable map. Also, sometimes you need to make more than one myAction.async. The pro is, it is quite explicit and in your control without too much ExecutionContext/ThreadLocal magic.
Here is some very rough sample code as a starter, for the manual solution:
def logErrorAndRethrow(myrequest:MyRequest, x:Throwable): Nothing = {
//log your error here in the format you like
throw x //you can do this or handle errors how you like
}
class MyRequest {
val attr : mutable.Map[String, String] = new mutable.HashMap[String, String]()
}
//make this a util to inject, or move it into a common parent controller
def myAsync(block: MyRequest => Future[Result] ): Action[AnyContent] = {
val myRequest = new MyRequest()
try {
Action.async(
block(myRequest).recover { case cause => logErrorAndRethrow(myRequest, cause) }
)
} catch {
case x:Throwable =>
logErrorAndRethrow(myRequest, x)
}
}
//the method your Route file refers to
def getStuff = myAsync { request:MyRequest =>
//execute your code here, passing around request as an implicit
Future.successful(Results.Ok)
}

Anybody implemented deadbolt or any other authorisation mechanism with securesocial?

I'm browsing around the web to find some kind of tutorial but I'm having trouble finding it.
I guess I could just use the twitter example provided with securesocial
example:
def onlyAdmin = SecuredAction(WithAuth("admin")) { implicit request =>
Ok("You could see this since you are admin")
}
case class WithAuth(role: String) extends Authorization {
def isAuthorized(user: Identity) = {
val existingDbUser = User.findUserByProviderUserId(user)
existingDbUser.hasRole(role)
}
User.findUserByProviderUserId(user) calls the db to find the stored user and it's roles.
I would prefer not to call the db every time and make use of the Identity.
How would you solve this?
That would be the right approach. You could, from the UserService.save() method return an instance of your own model (as long as it implements Identity). That would allow you to return your User object and then run user.hasRole(role) directly without querying the database again. But the query, needs to be done at some point.

How to re-boot liftweb?

I have my Boot.scala with boot method in it where i do my setup.
At the end, I make the call to LiftRules.statelessDispatchTable and append an new instance of my class that extends the RestHelper, which has the serve block.
At some point, I get a signal and need to change this class, so i need to make another call into the statelessDispatchTable to remove the original one and add a new one.
What's a good way to do this?
Thanks!
EDIT: I AM GOING TO UPDATE THE QUESTION WITH THE ANSWER I GOT FROM DAVID POLLAK:
You can't. Once your app is started, there's no way to change LiftRules.
However, the stuff you're adding to statelessDispatchTable is a PartialFunction[Req, Box[LiftResponse]] so you can write a PartialFunction that looks like:
object RestThing1 extends RestHelper { .... }
object RestThing2 extends RestHelper {....}
object MyDynamicRestThing extends PartialFunction[Req, Box[LiftResponse]] {
def isDefinedAt(in: Req): Boolean = if (testCondition) RestThing1.isDefinedAt(in) else RestThing2.isDefinedAt(in)
def apply(in: Req): Box[LiftRequest] = if (testCondition) RestThing1.apply(in) else RestThing2.apply(in)
}
LiftRules.statelessDispatchTable.append(MyDynamicRestThing)
You could create a second-level dispatch...e.g., an object that receives the requests, then according to some other logic proxies the requests on to the real handler. Then you don't have to mess with the top-level dispatch table at all.
Would really make sense to do this if what you are needing to do is toggle it based on a signal (e.g. it will revert back at some point), or if there is additional logic that would benefit from being in a proper abstraction.