This is a follow up from Java Play! 2 - User management with cookies
from the zentask example
public class Secured extends Security.Authenticator {
#Override
public String getUsername(Context ctx) {
return ctx.session().get("email");
}
#Override
public Result onUnauthorized(Context ctx) {
return redirect(routes.Application.login());
}
// Access rights
public static boolean isMemberOf(Long project) {
return Project.isMember(
project,
Context.current().request().username()
);
}
public static boolean isOwnerOf(Long task) {
return Task.isOwner(
task,
Context.current().request().username()
);
}
}
For me this doesn't really makes sense.
User gets the following cookie. for example "email=test#test.com"
If I go to a "secured" page , zentask only checks if email is not null. How can this be secure?
The reason of sessions are to get load off the db. But with this approach he has to constantly check if the user has the rights to on a secured page.
For me it doesn't really makes sense. Why is there a function getUsername? And why is the return type a string?
I want to do somthing like this:
User logs in and gets a cookie which looks somthing like this "value=randomString"
Safe the user OBJECT in the cache for example Cache.set(randomstring,userObject);
Now if the visitor comes back I check if his randomstring is in my cache, if yes check if the User object in the cash has the rights to be on the secured page.
I was able to achieve this, just without the #Security.Authenticated() annotation.
Is it possible to achieve this with this annotation?
It is just a sample, nothing else. You don't need to store a email in the cookie. You can for an example save some hash to identify logged user, or do some other matching.
Samples are as simple as possible, changing it to more sophisticated scenarios lays on the developers side.
BTW of course all Play's cookies are signed and I really doubt if you'll be able to manually change it.
Related
I'm trying to write my own ServerAuthModule, to use a custom login system.
If I understood everything right, what happens is that the container calls the validateRequest method for every incoming request, and that my SAM will check for credentials, and tell the container the username and groups of the user (if the credentials are right) via the CallbackHandler.
public class MySAM implements ServerAuthModule {
#Override
public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) throws AuthException {
// check user credentials
...
// set username and groups
CallerPrincipalCallback cpCallback = new CallerPrincipalCallback(clientSubject, username);
GroupPrincipalCallback gpCallback = new GroupPrincipalCallback(clientSubject, groups);
callbackHandler.handle(new Callback[]{cpCallback, gpCallback}
return AuthStatus.SUCCESS;
}
...
}
My problem now is, that when a user logs in, I don't know to which groups the user belongs. I can only check whether the user is in a given group. Is it somehow possible to give the container a method with which it can check whether a user is in a given group, instead of giving it an array with groups in the validateRequest method?
boolean isInGroup(String username, String group) {
// ask backend system
}
What you're doing looks right indeed.
There's no concept in JASPIC of handing the container a method like you intend. The container creates a set of Principals from the groups array you give it, and there's no room for a method there.
In Java EE, JACC should be able to do this. A JACC policy provider is consulted everytime the isUserInRole question needs to be answered and everytime it needs to be decided whether a user has some permission (eg allowed to access /adminpanel).
At that point you can do a kind of reverse check to see what role is required for a given Permission (using the role to Permission Maps that JACC builds up at startup time). With that role you can then use your own logic to determine if the user indeed has that role or group.
How can I set the language (i18n) not only from the users browser settings but also from subdomains (which should have higher priority) in playframework 2.2 (java)?
The following should work:
example.com -> english or german, depending on browser settings
en.example.com -> force english
de.example.com -> force german
The user should be able to switch between subdomains without losing the session.
Because I have a lot of java controllers, it would be great if the solution works in a centralized place (like Global.java with a filter which may be in scala).
You can use i.e. changeLang(String code) method of play.mvc.Controller superclass for this.
Then you need to tell to your language resolver, which domain uses which language us default, probebly using application.conf or databse records for this. Next depending on what you want to achieve, just use Global class to intercept all your request, or create a simple action which will change the language and they will return to the same page (so user can decide himself which language he wants to use).
It's some kind of cookie based machanism, so I'm not sure if it isn't required to perform forced page reload (ie. by redirecting to the same path) anyway I assume that you will tell us when you'll check it ;)
Edit:
that could be ie. like
public Action onRequest(final Http.Request request, final Method actionMethod) {
if (request.host().equals("de.yourdomain.tld")
&& (request.cookie("PLAY_LANG") == null || !request.cookie("PLAY_LANG").value().equals("de"))) {
return new Action.Simple() {
public Result call(Http.Context ctx) throws Throwable {
ctx.changeLang("de");
return redirect(request.path());
}
};
} else {
return super.onRequest(request, actionMethod);
}
}
Just make sure that you have de lang added in application.conf, otherwise you'll get beautiful, endless redirection loop. the PLAY_LANG is typical Play's cookie name for storing selected language.
I am using parse.com as my backend service for my Android application. I wish to make separation between my activities and parse, for this purpose I have created service class witch will bridge activities and parse (backend). Most parse functions are asynchronous and I don't really know how to handle them. For example if I want to login with a user I will call the service object that should execute login with parse login function. So here is my code in the activity:
LoginService login = new LoginService("username", "password");
login.login();
//from here it is not correct
if(login.getLoginStatus() == 2) {
//user loggedin
}...
and my service code is:
public LoginSrvice(String userName, String pass)
{
this.userName = userName;
this.pass = pass;
}
public void loginUser()
{
ParseUser.logInInBackground(userName, pass, new LogInCallback()
{
#Override
public void done(ParseUser user, ParseException e) {
if (user != null) {
logedIn = 1;
} else {
logedIn = 2;
}
}
});
}
public int getLoginStatus()
{
return logedIn;
}
My question is how should I do it right? how can i keep both activities and services separated but still wait for the response in the activity till the service class will get the callback from parse.
Thanks for the HELP in advance!
Well, I am not an Android developer, but in Java you can use the wait() notifiy() methods of objects for wait until something happens.
But take into consideration you can enter into in a race condition where you wait() after the notify() has been already called.
If a Service's lifecycle isn't tied to your Activity you can bind to it and then get a reference to the Service via the Binder object. The simplest communication method is to use a Messenger object in a way similar to this project.
In this particular instance, I assume you're waiting for the login before the user can use anything other than the login screen. You could probably perform the login in an AsyncTask or, even better, a Fragment/Loader model. In the appropriate callback method, you'd perform the post-login action.
I had a very similar question but for Parse and iOS. I posted the question here on SO along with the answer I found. You will probably find yourself writing Cloud Code in JavaScript for Parse. For that you will need to learn to use Promises. My solution to managing the asynchrony in iOS was to implement Promises in iOS. They allowed me to encapsulate my background Parse operations in a very clean way. The same trick may work for you.
It possible that the code I posted to GitHub will be of help, but it's in Objective-C.
-Bob
I'm not clear why you need an abstraction around Parse's API, but I would recommend something very simple. Parse's API already handles thread safety, so you can write your interface to query Parse state and KISS. I.e.
class UserAbstraction {
// You may find it useful to also use the callback object for other reasons.
public static void logIn(string userName, string password) {
ParseUser.logInInBackground(userName, password);
}
public static boolean isLoggedIn() {
return ParseUser.getCurrentUser() == null;
}
}
In my action i'd like to render different views (or maybe only display some other divs) depending on whether a user is authenticated or not.
Should i do something like this:
public static Result index() {
if (Context.current().request().username().equals("")) {
// user is NOT authenticated
return ok(welcome.render());
} else {
// user is authenticated
return ok(dashboard.render());
}
}
And how about checking if a user is authenticated in a view?
I know I can use the #Security.Authenticated(Secured.class) annotation, but how do things conditional?
Depends on what you're trying to achieve. If you only need to decide whether a user is logged in or not, you can use something like you wrote, in your controller classes, eg:
public static boolean loggedIn() {
return (session().get("userId") != null);
}
then in the static controller methods check whether the user is logged in:
if (!loggedIn()) {
return redirect(routes.Application.login());
}
Notice the use of the session() by which you can access the secure session cookie's map, and from there you can get the user id. If you want to implement more complex logic, eg. different actions for different user groups, then it's a different story.
Either use some maps in a cache with the authenticated user id-s and you validate the userId in the session, whether it's in the map, or alternatively you can use some property of the user (eg. a set of userRoles) and set what is visible accordingly. These are the most sensible ways I'm aware of.
(here's how you can use the session() of controller:
Controller,Session)
I am implementing a project with play 1.2.4, based on documentation the right way to handle validation is:
public static void signUp() {
render();
}
public static void doSignUp(#Required #Valid User user) {
if (validation.hasErrors()) {
params.flash();
validation.keep();
signUp();
}
user.create();
Application.index();
}
But based on samples provided with play, it seems that different approach is used:
public static void signUp() {
render();
}
public static void doSignUp(#Required #Valid User user) {
if (validation.hasErrors()) {
render("#signUp");
}
user.create();
Application.index();
}
For this small example the code difference is small, but in more complex examples it's not so simple.
Pros and cons I see are:
First approach:
Gives nice URLs to user
Always redirects after POST, so no confirm problem if user refreshes page
Only one method is responsible for filling renderArgs before calling
template
Compile time verification that signUp method exits if it gets renamed
Second approach:
Faster, no redirect/round-trip in browser
So what is the best practice? Which approach to use use along the application?
Let me go over your arguments:
First:
Gives nice URLs to user
The URL can always be fine in Play 1.x. You can use the following:
get /signUp myController.signUp
post /signUp myController.doSignUp
So the first argument doesn't matter.
Second:
Always redirects after POST, so no confirm problem if user refreshes page.
I think if a user makes a mistake and press F5 or refresh with other technique it's good if he get the same errors again. If the user should get the possibility to get a clean form, I prefer to have a cancel-button.
Third:
Only one method is responsible for filling renderArgs before calling template
Can't see the problem with render("#signUp");
Fourth:
Compile time verification that signUp method exits if it gets renamed.
Ok, this is an argument but I think it's weak. Will be false with play 2.0.
So I think both approaches can be good, depending on the situation. Specially if you have a large form, the redirect won't work. As default I would recommend the second solution.
However, I don't know how the situation with play 2.0 will be.
It depends. The first approach will be more RESTful. However because of the redirect, the errors and params need to be stored in the cookie to be retrieved.
Since there is a 4k limitation in the data stored in the cookie, this might not be suitable for large forms.