Display authenticated user info in header with secure social and play mvc - scala

I am currently working on authentication with play 2.x and securesocial plugin with scala.
My website should always have user info like "Username" "avatar image" etc in the header all the times unless user logout.
Now using secure social I am trying to get the current user of the request and made it implicit so that I can get the value for all the requests and avoid passing it as params to the template.
implicit def user(implicit request: RequestHeader) = SecureSocial.currentUser;
But the securesocial.core.SecureSocial requires a implicit request which I can't uness I have Action {} in my controller. Using implicit is very convenient but i find securesocial stuff kind of confusing.

The request object you receive in SecuredActions has a user already: request.user will give you the current one. If you pass this instance to your views you will have the user available. See SecuredRequest in SecureSocial.scala.

Try UserAwareAction instead of SecuredActions if you don't want a redirect

Related

How to override login of flask-security?

I want to do some customization when a user logs in. The problem is that the project is using flask-security which implicitly handles user login.
I want to check some records of users in the database when users log in.
How can I override "login" function in flask-security?
I saw a similar post, and tried it but it's not working.
Plus, it is not exactly what I want to do.
I maybe need to stop the default behavior in case of some users.
So, is anyone having this kind of issue? How can I do it?
You can override the login form when you are setting up Flask-Security:
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore, login_form=CustomLoginForm)
Then create your custom login form class that extends the default LoginForm. And override the validate function to do stuff before or after the login attempt.
from flask_security.forms import LoginForm
class CustomLoginForm(LoginForm):
def validate(self):
# Put code here if you want to do stuff before login attempt
response = super(CustomLoginForm, self).validate()
# Put code here if you want to do stuff after login attempt
return response
"reponse" will be True or False based on if the login was successful or not. If you want to check possible errors that occurred during the login attempt see "self.errors"
Greetings,
Kevin ;)
after registering the flask security extension, you can create an endpoint with the exact same name/route and it should override the one registered by Flask-security.
If you are using blueprints, make sure you register your blueprint before registering Flask-security.

Playframework(Scala): passing user model around

I wonder what's the best practise for passing user 'model' around. I take http request and convert it to user model in my controller. I don't want to explicitly add an argument to all the templates for this model, and neither to main.
What are the best practises for doing this?
THanks.
If you are logging in, and the user is your authenticated user, then you should put the user in a WrappedRequest and make your request implicit in your templates. If you use something like SecureSocial, then UserAwareAction will provide you with a RequestWithUser (see http://securesocial.ws/guide/user-service.html) and you can do things like
#()(implicit req:RequestWithUser)
Email = #{req.user.map(_.email)}
in your template.
Use the Session scope.
Here is documentation for Play 2.0
http://www.playframework.com/documentation/2.0.2/ScalaSessionFlash
So for example, on the login, add the user to the Session
And on logout remove the user from the Session
Cheers!

App Engine force login from facebook

I have a google app engine that handled logging in to Yahoo and Google though the OpenID mechanism and it works well. I have added the facebook connector (Javascript Library) and it to works well with the exception that I can't get the app to think it's authenticated. I know why this is occurring because Facebook provides its own "connect" and it's not OpenID.
Is there a way I can call the GAE framework once authenticated to allow for login: required pages to work?
I want to add others like twitter and microsoft, but it's a real pain if I can't get the GAE to honour the fact it's authenticated.
EDIT
Thanks to #Isaac below I did stumble upon this URL at facebook:
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/
The redirect URL you specifiy gets a few tokens that facebook thinks you need... in their case access_token={access-token}&expires={seconds-til-expiration}.
From the time when I managed to break my app because of the ajax loading I noticed that google OAuth put you back on /_ah/login?continue=<new final end point> which processed the tokens seemlessly and then did something within the framework to register the user as authenticated, then puts you back on the URL you specified in the first place. It's this I want to understand.
Further edit
I've found a few bits for example:
http://code.scotchmedia.com/engineauth/docs/index.html
It's python but it looks like it is possible to handle multiple authentication types from multiple vendors (the link shows things like twitter and facebook) so this does look possible.
I tried creating a new User on the framework, but there is no setCurrentUser() on the UserService object.
The only thing I can think of now is forging the authentication cookie. Anyone know the best way to do that?
I believe facebook has an oauth login flow. These links might help:
http://hayageek.com/facebook-javascript-sdk/
https://developers.facebook.com/docs/reference/dialogs/oauth/
https://developers.facebook.com/docs/facebook-login/
If you can't get oauth to work, you could use a #login_required decorator on your endpoints
import functools
def login_required(func):
#functools.wraps(func)
def decorated(self, *args, **kwargs):
current_user = users.get_current_user()
if current_user or check_facebook_login(self):
return func(self, *args, **kwargs)
elif self.request.method == 'GET':
self.redirect(users.create_login_url(self.request.url))
else:
self.response.headers['Content-Type'] = 'text/plain'
self.response.write('Forbidden')
self.error(403)
return decorated
class QueryHandler(webapp2.RequestHandler):
#login_required
def get(self):
...

Testing scala Play (2.2.1) controllers with CSRF protection

I've been having some problems testing controllers that use Play's CSRF protection. To demonstrate this, I've created a very simple Play application that minimally exhibits the problem.
https://github.com/adamnfish/csrftest
The full details are on the README of that repository, but to summarise here:
Consider a controller that is designed to handle a form submission. It has a GET method that uses CSRFAddToken and a POST method that uses CSRFCheck. The former adds a CSRF Token to the request so that a form field can be put in the rendered view, containing the valid token. When that form is submitted, if the CSRF check passes and the submission is valid, something else will happen (typically a redirect). If the form submission is not valid, the form submission is re-shown along with any errors so the user can correct the form and submit again.
This works great!
However, in the tests we now have some problems. To test the controller you can pass a fake request to it in the test. The CSRF check itself can be skipped by adding the nocheck header to the fake request but the view cannot be rendered because no token available to generate the form field. The test fails with a RuntimeException, "Missing CSRF Token (csrf.scala:51)".
Given that it works when it's actually running but not in the tests, it seems like this must be a problem with the way FakeRequests are run in Play tests but I may be doing something wrong. I've implemented the CSRF protection as described at http://www.playframework.com/documentation/2.2.1/ScalaCsrf and the testing as described at http://www.playframework.com/documentation/2.2.1/ScalaFunctionalTest. I'd appreciate any pointers if anyone has managed to test CSRF protected forms.
One solution is to test using a browser, eg Fluentlenium, as this will manage cookies etc, so the CSRF protection should all just work.
The other solution is to add a session to the FakeRequest so that it contains a token, eg:
FakeRequest().withSession("csrfToken" -> CSRF.SignedTokenProvider.generateToken)
Obviously if you're doing that a lot, you can create a help method to do that for you.
Bonus answer for those interested in Java: I got this to work in the Java version of Play Framework 2.2 by adding
.withSession(CSRF.TokenName(), CSRFFilter.apply$default$5().generateToken())
to fakeRequest()
Following on from #plade, I added a helper method to my base test class:
protected static FakeRequest csrfRequest(String method, String url) {
String token = CSRFFilter.apply$default$5().generateToken();
return fakeRequest(method, url + "?csrfToken=" + token)
.withSession(CSRF.TokenName(), token);
}
To those that are still interested: I managed to solve this problem globally by enabling CSRF protection in tests. The app will then create a token for every request that does not contain one. See my answer to this question
For those who might be interested, I created a trait for play 2.5.x :
https://stackoverflow.com/a/40259536/3894835
You can then use it in your tests requests like the addToken{} of the controller :
val fakeRequest = addToken(FakeRequest(/* params */))
I use the following method in my base integration test class:
def csrfRequest(method: String, uri: String)(implicit app: Application): FakeRequest[AnyContentAsEmpty.type] = {
val tokenProvider: TokenProvider = app.injector.instanceOf[TokenProvider]
val csrfTags = Map(Token.NameRequestTag -> "csrfToken", Token.RequestTag -> tokenProvider.generateToken)
FakeRequest(method, uri, FakeHeaders(), AnyContentAsEmpty, tags = csrfTags)
}
Then you can use it in your tests where you would use FakeRequest.

Showing loggedin User info in the header of my web app every time

I am working on play 2.1 with secure social integration. As of now, I was able to integrate securesocial with mongod db using SALAT. Now I am able to login/logout. But now what i want is if the user has logged in , then I need to show user info like avatar etc in the header of my web application and I am not sure how to get the user information in scala.html without passing as params from Controller. I can't do this everytime.
Do we have something similar to spring security which grabs user from session and use EL or spring taglib to display user info ???
Sad that this community is so inactive or dont want to answer this question. I still find spring and java communities answering the most basic questions even after several years. So here it is what I did.Any improvements or suggestions are highly welcome.
Wrote a method in my controller that would return user as a implicit method.
implicit def user(implicit request: RequestHeader):Option[Identity] = {
SecureSocial.currentUser
}
Pass this user to my template and make it implicit. Wondering why it can't directly use it from controller. I have to explicitly pass it which is very weird.
#(implicit user:Option[securesocial.core.Identity])
Since the user info has to be in all pages it has to be included in main template or main template call another template that renders user info.In my main template=>
#(title: String, nav: String = "")(content: Html)(implicit user:Option[securesocial.core.Identity]=None)
Then some view related code
#if(user.isDefined){
<li>
<a href="#securesocial.controllers.routes.LoginPage.logout()"/>Logout</li>
}else{
<li>
Login</li>
}
You can call a controller's method in a template to get something without passing it as a parameter:
#defining(Auth.getCurrentUserName()) {user =>
<div>Hello, #user</div>
}
Auth is a controller, getCurrentUserName() just gets some data from the session.
public static String getCurrentUserName() {
return session().get("username");
}
To make it simpler without providing implicit user, just call SecureSocial.currentUser() directly in your scala template.
You need to import it and then you can check if user is defined:
#import securesocial.core.SecureSocial
#if(SecureSocial.currentUser.isDefined) {
...
}