I'm using acegi 0.5.2 and enabled OpenID support. I would like to know how to accesss the URL (or username) returned by a provider (i.e. Google, Yahoo!). I can't find any docs about that so I traced the code of acegi and found this in GrailsOpenIdAuthenticationProvider:
OpenIDAuthenticationToken response = (OpenIDAuthenticationToken) authentication
OpenIDAuthenticationStatus status = response.status
// handle the various possibilites
if (status == OpenIDAuthenticationStatus.SUCCESS) {
// Lookup user details
UserDetails userDetails = _userDetailsService.loadUserByUsername(response.identityUrl)
return new GrailsOpenIdAuthenticationToken(userDetails, response.status, response.identityUrl)
}
it seems that the response.identityUrl contains what i need. How can get it from a controller's (or service's) space?
Thanks.
after a very long research and doing several trial and errors, i've found the solution.
acegi plugin provides a LoginController for your project and it has this action: authfail. inside its implementation, you can check the OpenID value thru this code:
println "openid = ${session['SPRING_SECURITY_LAST_EXCEPTION'].extraInformation}"
with that, you can then automatically create a new User record or do anything you want with the OpenID given by a provider.
Related
I am generating some endpoints and it works correctly, however, I would like to keep one session per client so I do not have to send the request by mail and password, but I am not sure of doing it.
This is an example of one of my endpoints
#Api(name = "test")
public class MyApi {
#ApiMethod(name = "printHi", httpMethod = "POST")
public Message imprimirHola(Input input) {
Message message = new Message();
if(datosCorrectos(input.getMail(), input.getPassword()))
message.setMessage("Hi");
else
message.setMessage("authentication failed");
return message;
}
}
After doing some research in the topic you have issues with, I have found the following information that can be useful for what you are trying to achieve.
Google Cloud Platform offers the Cloud Endpoints service, which has some available frameworks for user authentication. You can find detailed information and procedures about that in the documentation but, in short, you can use Firebase Auth, Auth0 or Google Accounts to authenticate a user against your endpoints (this link will help you decide which option suits you better).
However, in order to operate with one of those options, you will need that your API is managed by Cloud Endpoints, so you will have to follow this walkthrough to Add API Management to your API using OpenAPI.
Finally, here you have a working example on how to that using Java.
I know it is a lot of information, but I think you will be able to solve the authentication issue with your Java API just by reading more detailed information in this last documentation page, and move step by step in the "Getting Started" dropdown menu in the left of this page.
I was doing some research about drop-wizard security and authentication. Here is the link that I used http://howtodoinjava.com/dropwizard/dropwizard-basic-auth-security-example/.
My question is how to actually create new users, since VALID_USERS is a static final and can't be changed. I was thinking about creating a database, and that would consist of user object that contains the username and role ex. admin. (I don't need a password) But I am confused what I would return. In their example they returned Optional.of(new User(credentials.getUsername(), VALID_USERS.get(credentials.getUsername())));
Would I return a user object?
Essentially, I want to authenticate a user by the username and give them a role of authorization ex. admin, basic. But I guess I am confused how to generate a list of users and their roles. I was thinking of making a database, but I am not sure how exactly I would implement that.
public class AppBasicAuthenticator implements Authenticator<BasicCredentials, User>
{
private static final Map<String, Set<String>> VALID_USERS = ImmutableMap.of(
"guest", ImmutableSet.of(),
"user", ImmutableSet.of("USER"),
"admin", ImmutableSet.of("ADMIN", "USER")
);
#Override
public Optional<User> authenticate(BasicCredentials credentials) throws AuthenticationException
{
if (VALID_USERS.containsKey(credentials.getUsername()) && "password".equals(credentials.getPassword()))
{
return Optional.of(new User(credentials.getUsername(), VALID_USERS.get(credentials.getUsername())));
}
return Optional.empty();
}
}
in the latest version of DropWizard you can find it possible both to do Authentication and Authorization. The former, in a nutshell, instructs DropWizard to ask a user for credentials if you use basic authentication when she tries to access a resource or provide some other identity check. The latter allows one to grant a user access to various resources based on user's roles.
The are various possibilities how you can store user data and roles. Examples include a database which you mentioned, a LDAP server and a third-party identity management system.
If you are interested in Basic Authentication, you can take a look at my example here. A database is used to store user's credentials. Also, here is my little bit dated tutorial on DropWizard authentication. The code for the latest version is in the aforementioned example application.
To implement authentication only, you can skip adding roles and registering an Authorizer. To add authorization you can add a roles collection to your User entity and use annotations such as #RolesAllowed and #PermitAll along with Authorizer implementation to grant/deny access to your resources.
A link to DropWizard authentication docs is here.
Please feel free to ask more questions in comments and good luck.
I'm working on a cloud endpoints backend and want to restrict certain operations to admin users.
My current code works like this:
#ApiMethod(httpMethod = "PATCH", name = "item.update", path = "items")
public Item update(Item newObject, User user)
throws UnauthorizedException, OAuthRequestException {
OAuthService oAuthService = OAuthServiceFactory.getOAuthService();
if (!oAuthService.isUserAdmin()) {
throw new UnauthorizedException("Only admin users can modify content.");
}
...
}
I know app engine has a concept of user roles, but I'm curious if Endpoints
do. I've tried using the OAuthService.isUserAdmin() call but that doesn't
seem to be working out very well and the docs have a big old warning saying
Note: You should not confuse Endpoints auth with the auth for
non-Endpoints App Engine web apps described in the article on configuration settings
https://developers.google.com/appengine/articles/auth in the Admin
Console, where you also specify the user login requirement in your
web.xmlhttps://developers.google.com/appengine/docs/java/config/webxml#Security_and_Authentication
file. That approach is not used with Endpoints."
Do I have to create some sort of authorization myself that uses the User object that's passed into the update method? Any thoughts?
I had similar issues. Indeed OAuth user service has nothing to do with AppEngine user service. What I ended up doing was having a dedicated user type entity in my datastore where I store a specific flag (regular/admin) for each user. This flag is updated when I use AppEngine user service (i.e. so that the administrators I specified in the console get the proper admin flag).
In my endpoints API I get the current user authDomain and id, look up in my datastore to check whether it has the admin flag. The key of my user entity is composed of "authDomain:userId" and as I only support google user for now, it looks like (gmail.com:123456789)
This means that an administrator has to login once using the AppEngine UserService (i.e. a dedicated webpage in my case) so that the flag is properly updated
I needed to do the same thing and validate some endpoint to grant access only to admin members listed in the project console and used the same implementation presented above, but the oAuthService.isUserAdmin() accept one or more string parameters, this parameters are scopes that you specify and the Oauth uses to get user informations, in my case i just set this parameter and it works like the code bellow.
OAuthService authService = OAuthServiceFactory.getOAuthService();
User user;
try {
com.google.appengine.api.users.User currentUser =
authService.getCurrentUser(Constants.EMAIL_SCOPE);
if (currentUser != null && authService.isUserAdmin(Constants.EMAIL_SCOPE)) {
user = new User(currentUser.getEmail());
return user;
}
...
The EMAIL_SCOPE constant is defined by
public static final String EMAIL_SCOPE = "https://www.googleapis.com/auth/userinfo.email";
In my case i implemented an authenticator, to pass user information to endpoint only if it's admin user, you can read more about the authenticators if you want.
https://cloud.google.com/appengine/docs/java/endpoints/javadoc/com/google/api/server/spi/config/Authenticator
I'm developing a GWT app running on the Google App Engine and wondering if I need to worry about Cross-site request forgery or is that automatically taken care of for me?
For every RPC request that requires authentication, I have the following code:
public class BookServiceImpl extends RemoteServiceServlet implements
BookService {
public void deleteInventory(Key<Inventory> inventoryKey) throws NotLoggedInException, InvalidStateException, NotFoundException {
DAO dao = new DAO();
// This will throw NotLoggedInException if user is not logged in
User user = dao.getCurrentUser();
// Do deletion here
}
}
public final class DAO extends DAOBase {
public User getCurrentUser() throws NotLoggedInException {
currentUser = UserServiceFactory.getUserService().getCurrentUser();
if(currentUser == null) {
throw new NotLoggedInException();
}
return currentUser;
}
I couldn't find any documentation on how the UserService checks authentication. Is it enough to rely on the code above or do I need to to more? I'm a beginner at this, but from what I understand to avoid CSRF attacks some of the strategies are:
adding an authentication token in
the request payload instead of just
checking a cookie
checking the HTTP
Referer header
I can see that I have cookies set from Google with what look like SID values, but I can't tell from the serialized Java objects in the payloads if tokens are being passed or not. I also don't know if the Referer header is being used or not.
So, am I worrying about a non-issue? If not, what is the best strategy here? This is a common enough problem, that there must be standard solutions out there...
If you were to put the same code in a regular servlet, you'd surely be vulnerable to XSRF. But since you are using GWTs RemoteServiceServlet - the answer depends on the version of GWT you are using.
Starting with the yet-to-be-release GWT 2.1, the RPC mechanism adds request headers and validates the presence of these headers in RemoteServiceServlet. This has its limitations - in particular, older versions of flash allow you to send the request headers from a different domain, but it does make things more difficult for a potential attacker.
If you want to adequately protect yourself from XSRF, refer to Lombardi's Development blog. The blog discusses two techniques. The first is a simple change that ports 2.1 changes to older versions of GWT. The second approach requires duplicating the session identifier as a request parameter, and is the recommended way to protect against XSRF.
References
GWT RPC - Does it do enough to protect against CSRF?
Lombardi development blog on GWT RPC and XSRF
Security for GWT Applications
Is it possible to have multiple authentication methods for a java servlet? For example, have form based authentication in addition to open id based authentication so users can choose how they log in.
Yes.
However, I would suggest doing this using servlet filters instead of on the servlet itself.
http://brendangraetz.wordpress.com/2010/06/17/use-servlet-filters-for-user-authentication/
Follow the steps in that post, and override the isAuth() method such that it performs the authentication in however many modes you wish. In (very rough, untested) code:
#Override protected boolean isAuth()
{
String authMode = (String)(getSession(true).getAttribute("authMode"));
if (authMode == null) { return false; }
if (authMode.equals("open id") {
//do open id authentication steps here
//return true if authentication passes
}
else if (authMode.equals("some other authentication") {
//do some other authentication steps here
//return true if authentication passes
}
...
return false;
}
I am assuming of course that you already know how to implement the authentication steps in each mode individually.
The "trick" is to store a value in the HTTP session, immediately after the user performs the log in authentication, in the HTTP session. Based on this value, the filter will know what it should check or query whatever you specify before loading the servlet.
Another way of performing multiple authentication is with JAAS, the Java Authentication and Authorization service. Using JAAS, you can stack various authentication modules on top of each other, and you can configure which authentication module to run and which not to. This is called PAM (pluggable authentication module). Search for "J2SE JAAS" on Google or take a look at http://server.pramati.com/docstore/1270002/index.htm. These should help you to get started if you decide to go this route.
Yes it is possible, but it tends to be a bit tricky to implement.
For example, out-of-the-box SpringSecurity has support for local authentication, OpenId, X509 and other schemes, but combining them so that the user has alternative ways of logging in requires custom classes and custom wiring.