Bootstrap a grails app with dummy data when spring security facebook is involved - facebook

I've created a grails app that uses spring security to allow a user to authenticate via facebook, and I can successfully print out the facebook username onto one of the views, so thus far I don't have any issues.
My problem lies when trying to bootstrap my application with some sample data for my given facebook user, so I don't have to enter it every time the application starts up.
This is how I'm trying to bootstrap my own facebook account, I have the following in Bootstrap.groovy :
def adminRole = new AppRole(authority: 'ROLE_ADMIN').save(flush: true)
def userRole = new AppRole(authority: 'ROLE_USER').save(flush: true)
def testUser = new AppUser(username: 'facebook_563645402', enabled: true,
password: 'my-hashed-pw-here',
surveys: [jamies])
testUser.save(flush: true)
AppUserAppRole.create testUser, adminRole, true
For the record, I've added a hasMany for the surveys field mentioned above onto AppUser.
When I fire up the app and try to connect, I get the following error :
URI
/web/j_spring_security_facebook_check
Class
grails.validation.ValidationException
Message
Validation Error(s) occurred during save(): - Field error in object 'web.AppUser' on field 'username': rejected value [facebook_563645402]; codes [web.AppUser.username.unique.error.web.AppUser.username,web.AppUser.username.unique.error.username,web.AppUser.username.unique.error.java.lang.String,web.AppUser.username.unique.error,appUser.username.unique.error.web.AppUser.username,appUser.username.unique.error.username,appUser.username.unique.error.java.lang.String,appUser.username.unique.error,web.AppUser.username.unique.web.AppUser.username,web.AppUser.username.unique.username,web.AppUser.username.unique.java.lang.String,web.AppUser.username.unique,appUser.username.unique.web.AppUser.username,appUser.username.unique.username,appUser.username.unique.java.lang.String,appUser.username.unique,unique.web.AppUser.username,unique.username,unique.java.lang.String,unique]; arguments [username,class web.AppUser,facebook_563645402]; default message [Property [{0}] of class [{1}] with value [{2}] must be unique]
Which appears to complain about the username not being unique.
If by trying to bootstrap some data breaks the unique constraints on the facebook username, how can I possibly ever pre define any data for a user?
A quick Googling brings up a few suggestions (link1, Grails spring security bootstrap, but so far they haven't helped, any ideas?
EDIT:
Delving deeper into the error that grails reports, I can see that the root of the above error is located in DefaultFacebookAuthDao, line 135, which mentions the following :
AppUserDomainClazz.withTransaction {
appUser.save(flush: true, failOnError: true)
}
So, by authenticating, spring security attempts to save a user domain object...
EDIT 2 :
This is my Bootstrap.groovy
def testUser = new AppUser(username: 'facebook_563645402', enabled: true,
password: 'my-hashed-pw', surveys: [new Survey(1)])
testUser.save()
def fbUser = new FacebookUser(uid: 563645402)
fbUser.save(flush: true)
Both FacebookUser and AppUser were generated via the spring security facebook quickstart, with the only change being to add static hasMany = [surveys: Survey] to AppUser.

It looks like the data has already been predefined, otherwise there wouldn't be a unique constraint violation. Just check for the existence of the data and only create it if needed:
def adminRole = AppRole.findOrSaveByAuthority('ROLE_ADMIN')
def userRole = AppRole.findOrSaveByAuthority('ROLE_USER')
String username = 'facebook_563645402'
if (!AppUser.findByUsername(username)) {
def testUser = new AppUser(username: username, enabled: true,
password: 'my-hashed-pw-here')
testUser.addToSurveys(jamies)
testUser.save()
AppUserAppRole.create testUser, adminRole, true
}

Spring Security Facebook tries to create a new user with same username (facebook_563645402). Because it cannot find it by uid.
As I see from you code, you just create an user, with filled username, but it's not a facebook user, and uid field isn't filled. So, the plugin cannot find any facebook user and tries to create a new one, using 'facebook_563645402' username by default.
There two ways: or change username for user created in Bootstrap (if it's not a facebook user), or create a Facebook User also (will be used for authentication).

Related

How to generate different session ID every time an user logins

I am using Play Framework 2.5 for my web application.
In my application, the server side app generates a session id and put email address int it when provided creadentioal is valid, so that the app can judge where requested user is already logined or not using the session id.
Redirect(routes.Application.index).withSession("email" -> "xxx")
The server side app also discords session when an user logout.
Redirect(routes.Application.index).withSession
I checked the session id. The session id is always same even after I close my browser.
login
PLAY_SESSION=0b3fbd59f215c5df4dd937b508ef7cce42b65c56-email=pf%40ex
reload
PLAY_SESSION=0b3fbd59f215c5df4dd937b508ef7cce42b65c56-email=pf%40ex
logout
login
PLAY_SESSION=0b3fbd59f215c5df4dd937b508ef7cce42b65c56-email=pf%40ex
close the browser
login
PLAY_SESSION=0b3fbd59f215c5df4dd937b508ef7cce42b65c56-email=pf%40ex
It is easy for an attcher to guess session id for each account. So I want to generate different session ID every time an account logins. How can I do that?
Thanks.
From Docs
By default, there is no technical timeout for the Session. It expires when the user closes the web browser.
I am guessing as you didn't close the browser, the session remained the same after you logged-in again.
So, during logout, you can discard the old session using withNewSession and during login, create a new session using withSession
With the help of redis, you can generate random session id when user logs in every time.
That means that you will discard the play session instead of managing the user session using redis by youself.
Every time users login, you can generate session id for the user and restore it in redis and set the session expire time. when the request of users comes in, you can check the random session id within request.
update
when a user login, your back-end server can generate a randomId for the user, and put the random id into session. when the user logout, delete the random id. The code is like the following
class Application extends Controller {
def login() { implicit request =>
val canLogin: Boolean = // check the authority,such as secret code
if (canLogin) {
val loginRandomId = Random.alphanumeric // just an example, generate randomID as you want
//put key-value into redis. Maybe (loginRandomId, email) is what you want, and you can also set expiredate for the key
redis.set(loginRandomId, email)
Redirect(routes.Application.index).withSession("email" -> loginRandomId)
}
}
def index() { implicit request =>
val sessionValue = request.session.get("email");// sessionValue is randomId
val isExist = redis.exit(sessionValue)
if (isExist) {
//handle the request
} else {
// did not login, return
}
}
def logout() { implicit request =>
// when logout you should delete the key in redis
val sessionValue = request.session.get("email");
redis.delete(sessionValue)
}
}
Good luck

MembershipReboot with IdentityServer v3

I am having trouble extracting UserAccount properties from MembershipReboot in conjunction with Thinktecture IdentityServer. I have both up and running using the Sample repo here: https://github.com/identityserver/IdentityServer3.MembershipReboot
When I request the "openid profile" scope in an Implicit Grant Flow, I am missing a lot of the user account fields such as "given_name, middle_name", etc from the id_token and response from the userinfo endpoint. I understand this is because they need to be assigned in the GetClaimsFromAccount function.
I can see the requestedClaims come into the GetProfileDataAsync() function in the MembershipRebootUserService class and if I hover over the instance of TAccount in GetClaimsFromAccount I can see the Firstname, Lastname, etc properties appearing in the CustomUser dynamic proxy but I can't for the life of me work out how to access them and copy them into the claims collection?
More Info:
I suspect the issue is with this line:
claims.AddRange(userAccountService.MapClaims(account));
It looks like this should be converting the user account properties into claims but I dont get any back.
The way I understand it works is you add an option to your Scope object to return all of the claims for a user. IncludeAllClaimsForUser is the key property.
e.g.
new Scope
{
Enabled = true,
Name = "roles",
Type = ScopeType.Identity,
IncludeAllClaimsForUser = true,
Claims = new List<ScopeClaim>
{
new ScopeClaim("role")
}
}
My request includes the role property as well. This pulled back all the claims for the user from MR for me. My example is with Implicit flow btw.

How to assign role to newly created user

I am using meteor-roles packages and statically it creates the user admin#example.com, normal#example.com,.....
NOw I have a signup pages where the user can sign up.Initially I create the account by following code in client side, i am using coffeescritp:
Accounts.createUser
email: email
password: password
By doing these I can create the new user. Now how do I assign the role to that newly created user. I have roles- admin, normal, manage-users.
When doing these
id = Meteor.userId()
roles = "admin"
Roles.addUsersToRoles id, roles
I get the error "Exception while delivering result of invoking 'createUser' Error {} Error: Missing 'users' param
How can I assign the role dynamically.
Thank you in advance.!!!
You can only use Meteor.userId() if the user ID you are assigning the role(s) too is the current user. You would need to call Meteor.userLoginWith*() before trying to use Roles.addUsersToRoles(Meteor.userId(), roles).
I would suggest creating the user, assigning the roles, and then logging them in. If you log the user in prior to assigning an appropriate role, role-specific routes, allow functions, and publish functions may not behave properly.
I would suggest creating the user:
var userId = Accounts.createUser({
username: 'username',
email: 'email#email.com',
password: 'passwordString',
profile: {}
});
And then adding the user to the appropriate role:
var roles = ['admin', 'roleName'];
Roles.addUsersToRoles(userId, roles);
Then finally logging them in, after the role(s) has been assigned.

Entity framework - Avoid circular Relationship in serialization

I have two tables : Users & Profiles. A user has one profile (1:1), a profile can be affected to many users, each profile has many modules, each module has many actions.
I'm sending this object from an asmx to a aspx page using a direct service call.
I got an error because of lazy loading ... so I disabled the lazy loading.
this.Configuration.LazyLoadingEnabled = false;
this works fine, I got my user, with the profile null.
To build the menu tree I have to retrieve the profile. I included It :
User user = new User();
using (cduContext db = new cduContext())
{
// get the user
string encryptedPassword = Encryption.Encrypt(password);
user = (from u in db.Users
where u.UserName.Equals(login) &&
u.Password.Equals(encryptedPassword)
select u).FirstOrDefault();
// Include the users profile
user = db.Users.Include("Profile").FirstOrDefault();
}
return user;
I got this error in the javascript call function :
A circular reference was detected while serializing an object of type 'CDU.Entities.Models.User'.
When I made a quick watch on the user object, in asmx ( before sending it ) , I found, that the profile has included the list of the users who had this pofile, each user has his profile loaded ... etc
Any idea please ?
Note, your code should look like this:
using (cduContext db = new cduContext())
{
// get the user
string encryptedPassword = Encryption.Encrypt(password);
var user = from u in db.Users
where u.UserName.Equals(login) &&
u.Password.Equals(encryptedPassword)
select u;
// Include the users profile
return user.Include("Profile").FirstOrDefault();
}
In your code, you were throwing away the first query by overwriting it with the second. And there was no valid reason to create a blank user.
To address your problem, you're going to have make a decision on what you don't want to serialize. In your case, you probably don't want to serialize Profile.Users
You don't mention what serializer you're using. I'm assuming you're using the DataContract serializer?
EDIT:
You would mark your Profile.Users object with the [IgnoreDataMember] Attribute.

grails spring-security create user

Im having some problems creating new user from one of my controllers. I'm trying to add a new user to my MongoDB user collection like this. Authorities is defined as a Set of Role in the domain.
Role role = new Role(authority:"ROLE_USER")
User user = new User(username:params.username,email:params.email,password:params.password,enabled:params.enabled,
accountExpired:params.accountExpired,accountLocked:params.accountLocked,passwordExpired:params.passwordExpired,
authorities:[role])
if (user.validate()) {
user.save(flush:true)
} else {
user.errors.allErrors.each { println it }
}
The exact same code is able to create a user successfully from the bootstrap, but when i'm trying to do the same thing from a simple controller i'm getting this error:
2012-09-24 10:43:27,450 [http-8080-3] ERROR binding.GrailsDataBinder - Unable to auto-create type interface java.util.Set, class java.lang.InstantiationException thrown in constructor
a:662)
Looks like the problem is with data binding. You have to create User with authorities first and then add role using UserRole domain. Something like:
Role role = Role.findByAuthority("ROLE_USER")
User user = new User(username:params.username,email:params.email,password:params.password,enabled:params.enabled, accountExpired:params.accountExpired,accountLocked:params.accountLocked,passwordExpired:params.passwordExpired)
new UserRole(user: user, role: role).save(flush: flush, insert: true)
user.save(flush:true)
For more information how to create user with spring security, you may want to look at Spring Security UI