Sorry, we were not able to find a user with that username and password - spring

I installed the Spring Security core plug-in 1.2.7.3 on Grails 2.1.1, ran the s2-quickstart command, and then initialized the initial user and roles in the bootstrap.groovy, but I still cannot login. Text of the relevant piece of BootStrap.groovy follows:
if (SecRole.count == 0) {
def fUserRole = SecRole.findByAuthority('ROLE_FlowUser') ?: new SecRole(authority: 'ROLE_FlowUser').save(failOnError: true, flush: true)
def fAdminRole = SecRole.findByAuthority('ROLE_FlowAdmin') ?: new SecRole(authority: 'ROLE_FlowAdmin').save(failOnError: true, flush: true)
def bf = SecUser.findByUsername('bill') ?: new SecUser(
username: 'bill',
password: 'eagle',
firstName: 'bill',
lastName: 'fly',
email: 'bill.fly#baylorhealth.edu',
accountExpired: false,
accountLocked: false,
passwordExpired: false,
enabled: true
).save(failOnError: true, flush: true)
if (!bf.authorities.contains(fAdminRole)) {
SecUserSecRole.create bf, fAdminRole, true
}
if (!bf.authorities.contains(fUserRole)) {
SecUserSecRole.create bf, fUserRole, true
}
}
I am not encrypting the password in bootstrap, as seems to be the answer to most of the questions of this type. All four records are getting written to the database tables, but of course, I cannot tell if the password is encrypted correctly. My initial controller has the following annotation ahead of the class statement:
#Secured(['IS_AUTHENTICATED_FULLY'])
Also, I added the following to the config.groovy:
// Added by the Spring Security Core plugin:
grails.plugins.springsecurity.userLookup.userDomainClassName = 'cocktail.SecUser'
grails.plugins.springsecurity.userLookup.authorityJoinClassName = 'cocktail.SecUserSecRole'
grails.plugins.springsecurity.authority.className = 'cocktail.SecRole'
grails.plugins.springsecurity.password.algorithm = 'SHA-256'

Your password may be encoded two times (problem may occure if you are using multi datasources).
Try this :
class User {
...
transient bEncoded = false
...
protected void encodePassword() {
if (!bEncoded ) {
password = springSecurityService.encodePassword(password);
bEncoded = true;
}
}
}

My guess is the authorities.contains check is failing because of missing hashCode and equals methods in your role class. But if there are no roles (your 1st check) then the user wouldn't have any granted, so you can just remove those checks:
SecUserSecRole.create bf, fAdminRole, true
SecUserSecRole.create bf, fUserRole, true
If that doesn't fix it, it's most likely a password encoding issue - add debug logging for Spring Security and it should show you why it's failing; add debug 'org.springframework.security' in your log4j block in Config.groovy
p.s. if (SecRole.count == 0) { should be if (SecRole.count() == 0) { or just if (!SecRole.count()) {

Related

Secured users created in grails integration test are unauthorized but bootstrapped ones are

I'm using Grails Spring Security Core and the Grails Spring Security REST plugin and I'm just starting to get things set up. I initialized the plugins with a User class and an Authority class (defaults) and went to write an integration test, following a guide I found on the Grails website.
It said to put the following in an integration test:
def "test a user with the role ROLE_BOSS is able to access /api/announcements url"() {
when: 'login with the sherlock'
RestBuilder rest = new RestBuilder()
def resp = rest.post("http://localhost:${serverPort}/api/login") {
accept('application/json')
contentType('application/json')
json {
username = 'sherlock'
password = 'elementary'
}
}
then:
resp.status == 200
resp.json.roles.find { it == 'ROLE_BOSS' }
}
I went ahead and did something similar and it worked with a bootstrapped User, but when I tried to do the exact same test with a User created in the test method itself, it would fail with a 401 HTTP response code.
The code I'm trying to run:
void "check get access token"() {
given:
RestBuilder rest = new RestBuilder()
new User(username: "securitySpecTestUserName", password: "securitySpecTestPassword").save(flush: true)
assert User.count == 2
when:
def resp = rest.post("http://localhost:${serverPort}/api/login") {
accept('application/json')
contentType('application/json')
json {
username = "securitySpecTestUserName"
password = "securitySpecTestPassword"
}
}
then:
resp.status == 200
}
Note that the User.count == 2 assertion passes because there is one User in Bootstrap.groovy and the one create in the test method.
Why does this work and pass with the bootstrapped User without any issues at all but not the one created in the method? Is there a way I can write this integration test so that I can test the /api/login endpoint included in the grails-spring-security-rest plugin in this way?
The User you create in the given section is in a transaction that has not been committed. When you make the REST call, the api/login controller will be run in a new transaction that cannot see your un-committed User.
A few options (there are others)...
Create User in BootStrap.groovy
def init = { servletContext ->
environments {
test {
new User(username: "securitySpecTestUserName", password: "securitySpecTestPassword").save(flush: true)
}
}
}
Make REST calls to create the User - assuming you have such functionality
Create User in setup
#Integration
#Rollback
class UserIntSpec extends Specification {
def setup() {
new User(username: "securitySpecTestUserName", password: "securitySpecTestPassword").save(flush: true)
}
void "check get access token"() {
given:
RestBuilder rest = new RestBuilder()
when:
def response = rest.post("http://localhost:${serverPort}/api/login") {
accept('application/json')
contentType('application/json')
json {
username = "securitySpecTestUserName"
password = "securitySpecTestPassword"
}
}
then:
response.status == HttpServletResponse.SC_OK
when:
def token = response.json.access_token
then:
token
}
}
Note: In Grails >= 3.0, setup() is run in a separate transaction and persisted (why it solves your problem) which is not rolled back. Any data will need to be cleaned up manually.
I suggest you read the grails documentation on testing: Integration Testing

grails spring security CAS: cannot get login to work with non-local user

My grails 2.5.0 app uses Spring Security with the ldap and cas plugins. I trust this CAS server, so I need to allow users with no local (User, Role, UserRole tables) records to authenticate.
If I have a local user, everything works great. If I don't have a local user, then I get the CAS re-direct error followed by "Sorry, we were not able to find a user with that username and password." I read that the GormUserDetailsService supplied with CAS doesn't work for non-local users, so I've written my own MyUserDetailsService that implements GrailsUserDetailsService, and I've registered it in ./conf/spring/resources.groovy:
beans = {
userDetailsService(edu.uga.reg.MyUserDetailsService)
}
Unfortunately, this doesn't solve the problem: it works with local users, but gives the same re-direct+user not found error if the user isn't in my local database. Here's MyUserDetailService code:
import grails.plugin.springsecurity.SpringSecurityUtils
import grails.plugin.springsecurity.userdetails.GrailsUser
import grails.plugin.springsecurity.userdetails.GrailsUserDetailsService
import grails.transaction.Transactional
import org.springframework.security.core.authority.GrantedAuthorityImpl
import edu.uga.reg.User
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.core.userdetails.UsernameNotFoundException
class MyUserDetailsService implements GrailsUserDetailsService {
/**
* Some Spring Security classes (e.g. RoleHierarchyVoter) expect at least
* one role, so we give a user with no granted roles this one which gets
* past that restriction but doesn't grant anything.
*/
static final List NO_ROLES =
[new GrantedAuthorityImpl(SpringSecurityUtils.NO_ROLE)]
UserDetails loadUserByUsername(String username, boolean loadRoles)
throws UsernameNotFoundException {
return loadUserByUsername(username)
}
UserDetails loadUserByUsername(String username) {
def user = User.findByUsername(username)
// No local user in my db: create one from this username
if (!user)
return new GrailsUser(username, '', true, true, true, NO_ROLES, 999)
def authorities = user.authorities.collect {
new GrantedAuthorityImpl(it.authority)
}
return new GrailsUser(user.username, user.password,
user.enabled, !user.accountExpired, !user.passwordExpired,
!user.accountLocked, authorities ?: NO_ROLES, user.id)
}
}
Here are my cas settings in Config.groovy:
grails.plugin.springsecurity.providerNames = ['casAuthenticationProvider']
grails.plugin.springsecurity.useCAS = true
grails.plugin.springsecurity.cas.active = true
grails.plugin.springsecurity.cas.loginUri = '/login'
grails.plugin.springsecurity.cas.serverUrlPrefix = 'https://cas.dev.server/cas'
grails.plugin.springsecurity.cas.serviceUrl = 'https://apps-dev.server:8743/CASIS/j_spring_cas_security_check'
grails.plugin.springsecurity.logout.afterLogoutUrl = 'https://cas.dev.server/cas/logout?url=http://apps-dev.server:8743/CASIS/'
//default cas settings
grails.plugin.springsecurity.cas.sendRenew = false
grails.plugin.springsecurity.cas.key = 'grails-spring-security-cas'
grails.plugin.springsecurity.cas.artifactParameter = 'ticket'
grails.plugin.springsecurity.cas.serviceParameter = 'service'
grails.plugin.springsecurity.cas.filterProcessesUrl = '/j_spring_cas_security_check'
grails.plugin.springsecurity.cas.useSingleSignout = true
grails.plugin.springsecurity.cas.serverUrlEncoding = 'UTF-8'
grails.plugin.springsecurity.cas.proxyCallbackUrl = null
grails.plugin.springsecurity.cas.proxyReceptorUrl = null
Again, CAS works fine if the user is in my local db, but fails otherwise. What am I missing? Thanks.
The answer to my problem is trivial. It's always a good idea to pass the correct number of arguments to the constructor. Instead of:
return new GrailsUser(username, '', true, true, true, NO_ROLES, 999)
I simply needed:
return new GrailsUser(username, '', true, true, true, true, NO_ROLES, 999)
And my user is setup as the principal!

Grails Spring Security Rest - 403 Forbidden

So I just started learning Grails, and I am trying incorporate the Spring Security REST plugin into my app, the plugin is installed in addition to spring security core which is working. In my REST client, when I hit "api/login" I am able to get an access token and it says I have the role of "ROLE_ADMIN", but then when I try to hit something using that, I keep getting a 403 Forbidden. In Postman, the REST client I am using, I have my Authorization header with "Bearer {key}", with my url of "http://localhost:8080/test/api/secret" and it gives the 403 error. I am trying to setup the log4j logging to see any other issues, but does anyone know what I should look into, any help would be appreciated. I provided my classes below if that helps, I generally used default values for everything such as the UrlMappings.
RandomController.groovy
package test
import grails.plugin.springsecurity.annotation.Secured
#Secured(['IS_AUTHENTICATED_ANONYMOUSLY'])
class MyController {
#Secured(['ROLE_ADMIN'])
def secret() {
render "You have ACCESS!!!"
}
}
Bootstrap.groovy
class BootStrap {
def init = { servletContext ->
def adminRole = new SecRole(authority: 'ROLE_ADMIN').save(flush: true)
def testUser = new SecUser(username: 'bob', password: 'test')
testUser.save(flush: true)
SecUserSecRole.create testUser, adminRole, true
}
def destroy = {
}
}
UrlMappings.groovy
class UrlMappings {
static mappings = {
"/$controller/$action?/$id?(.$format)?"{
constraints {
// apply constraints here
}
}
"/api/$controller/$action?/$id?(.$format)?"{ constraints { // apply constraints here
} }
"/"(view:"/index")
"500"(view:'/error')
}
}
For what I can see from the code you posted, if you invoke url http://localhost:8080/test/api/secret, it should execute default action (maybe index) in SecretController but the controller you posted is called MyController.
To investigate further, you should enable more verbose logging using log4j configuration as suggested in the doc http://alvarosanchez.github.io/grails-spring-security-rest/1.5.1/docs/guide/debugging.html

Allowing only the current user to the edit page in grails

I am building a web portal in grails with spring security. In my portal The users having USER, ADMIN role has the privilege to edit their profile. By login in USER role go to edit page /RITE/user/myedit/2 and can edit. Problem is when i editing the url /RITE/user/myedit/2 , by /RITE/user/myedit/1 I am able to see the ADMI privileged user. I tried annotations, but didnt work . How can I avoid this?
#Secured(['ROLE_ADMIN','ROLE_USER'])
def mylist(Integer max)
{
def user = springSecurityService.currentUser
def c= User.findByUsername(user.username)
params.max = Math.min(max ?: 10, 100)
[userInstanceList: c]
}
#Secured(['ROLE_ADMIN','ROLE_USER'])
def myshow(Long id) {
//userService.show(id)
//println "in myshow"
def user = springSecurityService.currentUser
UserDetails currentUser = springSecurityService.principal
if(id==currentUser.id){
def userInstance = User.get(id)
if (!userInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), id])
redirect(action: "mylist")
return
}
[userInstance: userInstance]
}
}
#Secured(['ROLE_ADMIN','ROLE_USER'])
def myedit(Long id) {
def user = springSecurityService.currentUser
UserDetails currentUser = springSecurityService.principal
def c= User.findByUsername(user.username)
if(id == user.id ){
def userInstance = User.get(c.id)
if (!userInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), id])
println("not allowed")
redirect(action: "mylist")
return
}
[userInstance: userInstance]
}
}
You need a manual implementation of something that express:
if( User.findByUsername(springSecurityService.currentUser.username).id
!= id_ofEditedUser) {
throw new AccessDeniedException("one can only edit its own stuff");
}
Ralph's suggestion is accurate but I don't generally do it this way when we're talking about user information that is only editable by the authenticated user. You'd be better off not requiring an ID at all:
def myedit() {
// this is the authenticated user, therefor, this is the information being edited
def userInstance = User.findByUsername(springSecurityService.principal.username)
[userInstance: userInstance]
}
If you want the ability for someone other than the specific user to edit user info, an Admin for example, provide an administrative action specifically for that. It will make more sense 6 months from now when have to look at the code again.

Keep a Play 2 application private on heroku

I'm using Heroku to host a Play 2 application for the purpose of testing and playing around. I'd like the application to be "private" at this point which means that every aspect of the application should only be visible to certain users.
Normally, I would just use an htaccess file with one single user/password, but that's a specific thing of Apache of course and doesn't help me in this case.
The protection doesn't have to be "strong". The main aim is to keep away bots and random visitors
It would be great if I didn't have to "pollute" the code of my play application. I'd prefer to have some external mechanism to achieve that. If there is no other way than to realize it using play itself, the solution should be loosely coupled from the rest of my play application.
How could I achieve that?
edit: to emphasize it: what I want to achieve won't be part of the final application in production mode. So it neither has to be super secure, nor super engineered.
Adreas example is correct but it is from play 2.1 and in play 2.2 the signature of Filter.apply has changed a little bit, this should work better with 2.2:
class BasicAuth extends Filter {
val username = "stig"
val password = "secretpassword"
override def apply(next: RequestHeader => Future[SimpleResult])(request: RequestHeader): Future[SimpleResult] = {
request.headers.get("Authorization").flatMap { authorization =>
authorization.split(" ").drop(1).headOption.filter { encoded =>
new String(org.apache.commons.codec.binary.Base64.decodeBase64(encoded.getBytes)).split(":").toList match {
case u :: p :: Nil if u == username && password == p => true
case _ => false
}
}.map(_ => next(request))
}.getOrElse {
Future.successful(Results.Unauthorized.withHeaders("WWW-Authenticate" -> """Basic realm="MyApp Staging""""))
}
}
}
I dont think Heroku offers a solution for this. I ended up implementing a Basic access authentication filter and used it in the Global object. It looks something like this
class HerokuHttpAuth extends Filter {
object Conf {
val isStaging = true // read a config instead of hard coding
val user = "theusername"
val password = "thepassword"
}
override def apply(next: RequestHeader => Result)(request: RequestHeader): Result = {
if (Conf.isStaging) {
request.headers.get("Authorization").flatMap { authorization =>
authorization.split(" ").drop(1).headOption.filter { encoded =>
new String(org.apache.commons.codec.binary.Base64.decodeBase64(encoded.getBytes)).split(":").toList match {
case u :: p :: Nil if u == Conf.user && Conf.password == p => true
case _ => false
}
}.map(_ => next(request))
}.getOrElse {
Results.Unauthorized.withHeaders("WWW-Authenticate" -> """Basic realm="MyApp Staging"""")
}
} else {
next(request)
}
}
}

Resources