Grails Spring Security Custom UserDetailsService (goal of Email in place of Username) - grails

I am using Grails Spring Security Plugin 1.2.7.3 and would like to have the User authenticate via Email Address and Password. I would like Email Address to be the primary Login ID.
I came across the following Nabble post regarding case insensitive usernames, where the original poster is attempting to do the same. However, I was a bit confused on a few points:
I understand that I need to write my own implementation of UserDetailsService and register it in grails-app/conf/spring/resources.groovy.
However, I wasn't sure which folder the custom implementation of UserDetailsService should go (best practices). My guesses are either /grails-app/services, /grails-app/utils, or /src/groovy. Has anyone done this before and where is the best place for the custom UserDetailsService?
I read this chapter in the Docs: http://grails-plugins.github.com/grails-spring-security-core/docs/manual/guide/11%20Custom%20UserDetailsService.html but I didn't really see guidance on what Grails folder to put it in.
I created my User domain class via s2 command:
s2-quickstart com.philiptenn.security User Role Requestmap
If I were to rename the field User.username to User.email so that my code is clearer, will I be in for a world of hurt?
I did a Find Usages on this field, and one stuck out in DefaultSecurityConfig.groovy: userLookup.usernamePropertyName = 'username'
Could I just update this to read:
DefaultSecurityConfig.groovy: userLookup.usernamePropertyName = 'email'
Thank you.

As you pointed out, you can override the default security configs in your own Config.groovy, the options all start with grails.plugins.springsecurity, so it would be grails.plugins.springsecurity.userLookup.usernamePropertyName = 'email' (docs). That's the first thing I'd try. If you check out the source of the GormUserDetailsService, the default userDetailsService, you'll see it uses that property for the lookup.

Related

UserManager.AddPassword doesn't work as expected

I am using ASP.NET Identity for membership in MVC5 and have a page for the admin user to manage users and roles. I am trying to allow the admin to change the password for any other user if he needs to do so. I am using this code to perform the task:
userManager.RemovePassword(userId);
userManager.AddPassword(userId, newPassword);
Seems simple enough, but when I try to login with the new password I just created, I can't; I get the invalid password message.
I tried to investigate this issue further by trying to find out how it hashes passwords and discovered this:
string hashed = userManager.PasswordHasher.HashPassword("some password");
Firstly, I am assuming this password hasher is what AddPassword() is using internally.
Secondly, I noticed that each time I run HashPassword('some password'), I get a completely different hash returned to me.
I don't get it...
Alright, I found the problem, it's because of the following line of code in the AccountController:
var user = await UserManager.FindAsync(model.Email, model.Password);
What's happening here is that FindAsync requires a username, not an email and with the user I was testing, the username and email were different.
I wondered if maybe I changed the code in the Login action to pass in the email address and didn't remember... so I created a new MVC5 project and used Nuget to updated to the latest version... well, it looks like that's a bug! Yes, the default implementation actually passes in the email address to FindAsync. Obviously this is because when you register a new user, it sets up the username to be the email address (so they are the same and it doesn't matter). However, they didn't take into account the fact that someone may want to change their username!
Solved!

How does one test AuthController generated by Shiro Grails plugin?

I'm getting very frustrated with the Shiro plugin for Grails. First, I'm trying to set up an ini-based SecurityManager like the beginner tutorial for Shiro suggests, and there's nothing in the documentation that tells me how things get configured. So, after struggling to figure it out, and ultimately failing, I just concede that I have to go with the DbRealm that was generated with the quickstart command. Now I'm trying to discover how things are working by creating a unit test for the generated AuthController. Here's my test code:
void "registered user logs in with valid credentials"() {
given: "user 'root' is registered"
def username = "root"
def password = "secret"
new User(username: username, password: password).save();
when: "user logs in with correct credentials"
params.username = username
params.password = password
controller.signIn();
then: "user should be authenticated"
assertTrue SecurityUtils.subject.authenticated
}
I'm still not sure how to verify the user is actually logged in so I thought the code in the then block should be fine for now. However, every time I try testing the app with grails test-app, I always get:
org.apache.shiro.UnavailableSecurityManagerException: No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton. This is an invalid application configuration.
at org.apache.shiro.SecurityUtils.getSecurityManager(SecurityUtils.java:123)
I'm not exactly new to Grails but it's been a very long time since I last used it, and I never really had that that much exposure to the framework, anyway. However, I know it's supposed to make things less complicated to set up, but the Shiro plugin is giving me a difficult time.
So, how do I go about configuring my app, and/or testing the generated AuthController?

How to restrict editing to the user who created with Grails

Any user can create his/her own robot. A robot should be edited only by the creator or an administrator.
The next code works perfectly and it is an easy and simple solution:
import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils
class RobotController {
def springSecurityService
def edit() {
if (Robot.get(params.id).usuario.username == springSecurityService.authentication.name
|| SpringSecurityUtils.ifAnyGranted("ROL_ADMIN,ROL_SUPERADMIN"))
println "editing allowed"
else
println "editing denied"
}
}
But my teacher recommended me to secure the web using Config.groovy. The next code does not work:
grails.plugins.springsecurity.interceptUrlMap = [
'/index.gsp': ["isAuthenticated()"],
'/robot/edit/**': ["Robot.get(params.id).usuario.username == springSecurityService.authentication.name
|| hasAnyRole('ROL_ADMIN','ROL_SUPERADMIN')"],
'/robot/**': ["isAuthenticated()"]
]
It does not work because different reasons:
It is not possible to call the domain class Robot in Config.groovy
params.id has no sense in this place
The Java "or" (||) is not valid here. I tried other ways with not luck. The Groovy documentation is not clear for me.
Is possible to do it in Config.groovy? If not, the correct way would be using <sec:access> ... </sec:access> somehow?
I don't think you can do that kind of thing with plain Spring Security core.
Your teacher is right in the sense that you probably shouldn't implement the security in an ad-hoc manner, but you don't necessarily should do it in the Config.groovy -- that is a bit limiting.
You probably want to use the Spring Security ACL plugin, it adds some more domain classes and allows you to set up the access control with much more fine grained detail.
Check out the official docs. It may take a little while for you to learn it, but it is much better than rolling out your own ACL mechanism.

sfGuardAuth across multiple apps

I've got 3 apps: Backend, Frontend and Members.
And I've got 2 credentials: Administrators and Members.
Administrators are imported by default but Members are created in the Backend.
When a Member is created, an event handler also inserts this Member as a sf_guard_user and of course, the proper relations in sf_guard_user_group and sf_guard_user_permission.
That's the boring part, now the fun:
Frontend is not secured, but Members is and using these credentials: [administrator, member].
According to all this, Members created in the Backend that also get inserted (correctly as far as I can tell) should be able to login to the Members secured app, since they get the member group/permission/credential.
This is not happenning, the only ones that can login to the Members app are the administrators, which is not wrong, but either is the fact that correctly created Member users can't login to it.
The error thrown by the guard is the classic: The username and/or password is invalid.
Now that I edit the error, the salt comes to mind: How would one emulate the inserting of the salt as the guard does it? Maybe that's what I'm not inserting correctly (or inserting at all) and thus the password invalid error (and in fact everythine else I've described is ok! omg)
And that's my problem.
Thanks in advance :)
[administrator, member] means both are required, I believe.
I think you want [[administrator, member]] for the credential requirement.
Also, yes, you will want to make sure you use a salt, and set the algo.
parent::_set('password', call_user_func_array($algorithm, array($salt.$password)));
Salt before password, as well.

LDAP through Ruby or Rails

I've been attempting to hook a Rails application up to ActiveDirectory. I'll be synchronizing data about users between AD and a database, currently MySQL (but may turn into SQL Server or PostgreSQL).
I've checked out activedirectory-ruby, and it looks really buggy (for a 1.0 release!?). It wraps Net::LDAP, so I tried using that instead, but it's really close to the actual syntax of LDAP, and I enjoyed the abstraction of ActiveDirectory-Ruby because of its ActiveRecord-like syntax.
Is there an elegant ORM-type tool for a directory server? Better yet, if there were some kind of scaffolding tool for LDAP (CRUD for users, groups, organizational units, and so on). Then I could quickly integrate that with my existing authentication code though Authlogic, and keep all of the data synchronized.
Here is sample code I use with the net-ldap gem to verify user logins from the ActiveDirectory server at my work:
require 'net/ldap' # gem install net-ldap
def name_for_login( email, password )
email = email[/\A\w+/].downcase # Throw out the domain, if it was there
email << "#mycompany.com" # I only check people in my company
ldap = Net::LDAP.new(
host: 'ldap.mycompany.com', # Thankfully this is a standard name
auth: { method: :simple, email: email, password:password }
)
if ldap.bind
# Yay, the login credentials were valid!
# Get the user's full name and return it
ldap.search(
base: "OU=Users,OU=Accounts,DC=mycompany,DC=com",
filter: Net::LDAP::Filter.eq( "mail", email ),
attributes: %w[ displayName ],
return_result:true
).first.displayName.first
end
end
The first.displayName.first code at the end looks a little goofy, and so might benefit from some explanation:
Net::LDAP#search always returns an array of results, even if you end up matching only one entry. The first call to first finds the first (and presumably only) entry that matched the email address.
The Net::LDAP::Entry returned by the search conveniently lets you access attributes via method name, so some_entry.displayName is the same as some_entry['displayName'].
Every attribute in a Net::LDAP::Entry is always an array of values, even when only one value is present. Although it might be silly to have a user with multiple "displayName" values, LDAP's generic nature means that it's possible. The final first invocation turns the array-of-one-string into just the string for the user's full name.
Have you tried looking at these:
http://saush.wordpress.com/2006/07/18/rubyrails-user-authentication-with-microsoft-active-directory/
http://xaop.com/blog/2008/06/17/simple-windows-active-directory-ldap-authentication-with-rails/
This is more anecdotal than a real answer...
I had a similar experience using Samba and OpenLDAP server. I couldn't find a library to really do what I wanted so I rolled my own helper classes.
I used ldapbrowser to see what fields Samba filled in when I created a user the "official" way and and basically duplicated that.
The only tricky/non-standard LDAP thing was the crazy password encryption we have:
userPass:
"{MD5}" + Base64.encode64(Digest::MD5.digest(pass))
sambaNTPassword:
OpenSSL::Digest::MD4.hexdigest(Iconv.iconv("UCS-2", "UTF-8", pass).join).upcase
For the def authenticate(user, pass) function I try to get LDAP to bind to the domain using their credentials, if I catch an exception then the login failed, otherwise let them in.
Sorry, cannot comment yet... perhaps someone can relocate this appropriately.
#Phrogz's solution works well, but bind_simple (inside bind) raises an Net::LDAP::LdapError exception due to auth[:username] not being set as shown here:
https://github.com/ruby-ldap/ruby-net-ldap/blob/master/lib/net/ldap.rb
The corrected replaces:
auth: { method: :simple, email: email, password:password }
with:
auth: { method: :simple, username: email, password:password }
I began using ruby-activedirectory, and even extended it/fixed a few things, hosting judy-activedirectory in Github.
Doing the next iteration, I've discovered ActiveLdap has a much better code base, and I'm seriously contemplating switching to it. Does anyone have personal experience with this?
Have you checked out thoughtbot's ldap-activerecord-gateway? It might be something for you to consider...
http://github.com/thoughtbot/ldap-activerecord-gateway/tree/master

Resources