How does one test AuthController generated by Shiro Grails plugin? - grails

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?

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!

Design issue with automating a Then step in my BDD scenario

I am quite new to BDD, I am trying to use BDD in order to develop a simple signup module for a website.
I have the following scenario:
Scenario: An anonymous visitor successfully signs up with the website
Given the following email address: john.smith#gmail.com and a chosen member status of childminder and the following password: ------
When the anonymous visitor signs up
Then a confirmation email with activation information is sent to the anonymous visitor
I am quite at a loss automating the Then step ("Then a confirmation email with activation information is sent to the anonymous visitor")
Here is what I have undertaken (with JBehave):
#Given("the following email address: $email and a chosen member status of $status and the following password: $password")
public void anonymousVisitorEntersDetails(String email, String status, String password) {
pages.home().open();
pages.home().enterDetails(email, status, password);
}
#When("the anonymous visitor signs up")
public void anonymousVisitorDoesRegister(String login, String password) {
pages.home().doRegister();
}
#Then("a confirmation email with activation information is sent to the anonymous visitor")
public void activationInformationIsSent() {
//TODO ??
}
The issue I have is not so much a tool issue as a design issue. I would be grateful if some experienced BDD practitionner would help me sort this out...
Let's start with your Given. This sets up the context. If I understand your scenario, relevant things that might be of interest are:
- not logged in
- on the home (or registration) page
Do not mention user details here.
Next, your When step specifies what user details the anonymous user registers with.
Finally, the Then step needs to check that a confirmation email is sent. Although it is tempting to send an email & check that it arrives, this would IMO be a mistake. Email is not guaranteed to arrive and is slow in any case. Keep your test suite fast and robust.
Instead use the wording of your When statement, or a tag on the scenario, to indicate that your app should be constructed with a mock email component. In your Then step you can interrogate the mock to verify that it has been called as expected.
Somewhere in your tests you will still need an integration and/or acceptance test to validate that the 'real' email component has been deployed correctly. This might be a manual test, or it might be a slow & temperamental automated test that logs into a mail client and polls until an email with the expected content arrives.

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

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.

current sessions in Grails

I am a beginner in Grails 2.0 framework and I am trying to follow this tutorial http://grails.org/Simple+Avatar+Uploader . I implemented this code but I am getting an error in UserController.groovy at this line 'def user = User.current(session)' as ' No such property: User for class: grailtwitter.PersonController' I assume that this line takes the user's current session. I am looking for an explanation of how this works ?
This code is incomplete. The controller presupposes that you have a way of identifying the currently logged in user. Implicitly the line def user = User.current(session) assumes that you have defined a current() method on the user class itself that takes in a session and presumably uses some field that you've set in it to retrieve a User. That would be kind of dumb.
A common way to do this would be to build your own authentication mechanism. Note that this is a naive practice and you are far better off using Spring Security Core unless you want to leave your application open for gaping security holes. But, for practice, something like:
def login = {
//if you're stupid enough to store your passwords in plain text and not sanitize user inputs, you deserve to be hacked
def user = User.findByPassword(params.password)
if(user){
session.user = user
}
}
You could then replace the offending line in the tutorial (--def user = User.current(session)--) with
def user = session.user ?: new User(userid:"I'm a little teapot")
Before you go much further, you probably want to walk through this free eBook on Grails before you get much further. Also highly recommend Grails in Action.
When I have run into this in the past it's because I didn't import the class and Grails/Groovy thinks I'm trying to access a variable called User rather than a method on the class.

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