私は Grails 2.4.4 を使用しており、Spring Security Core 2.0-RC4、機能的な Spock 0.7 を備えた Spring Security REST 1.5.0.M1 を使用しています。
機能テストを使用して、作成中の REST API のコントローラーをテストしています。テストをセットアップするときUser
、管理者Role
を作成し、次に を作成しUserRole
ます。User
スポック機能テストの内部に適切な資格情報が保持されていることを確認すると、すべて問題ないことがわかります。
ただし、認証GormUserDetailsService
時に を呼び出しても何も得られませんUser.findWhere(username:<appropriate username>)
。具体的な方法はGormUserDetailsService
こちらから:
UserDetails loadUserByUsername(String username, boolean loadRoles) throws UsernameNotFoundException {
def conf = SpringSecurityUtils.securityConfig
String userClassName = conf.userLookup.userDomainClassName
def dc = grailsApplication.getDomainClass(userClassName)
if (!dc) {
throw new IllegalArgumentException("The specified user domain class '$userClassName' is not a domain class")
}
Class<?> User = dc.clazz
User.withTransaction { status ->
def user = User.findWhere((conf.userLookup.usernamePropertyName): username)
if (!user) {
log.warn "User not found: $username"
throw new NoStackUsernameNotFoundException()
}
Collection<GrantedAuthority> authorities = loadAuthorities(user, username, loadRoles)
createUserDetails user, authorities
}
}
問題はUser.findWhere()
、User インスタンスをデータベースにフラッシュしたことを機能テストで確認したにもかかわらず、呼び出しで何も見つからないことです。このメソッドのブロック内の呼び出しですべてのUserRole
とUser
を印刷しようとしましたが、まだ何も返されません。findAll()
withTransaction
誰にも考えはありますか?自分ではない何かをあざける必要がありますか? @TestFor
機能テストで@Mock
注釈を使用しています。
アップデート
これが私の機能テストの簡単なバージョンです。
package com.help
import grails.plugins.rest.client.RestBuilder
import grails.plugins.rest.client.RestResponse
import grails.test.mixin.Mock
import grails.test.mixin.TestFor
import groovy.json.JsonBuilder
import org.codehaus.groovy.grails.web.json.JSONObject
import spock.lang.Shared
import spock.lang.Specification
@TestFor(PersonController)
@Mock([Person, Role, PersonRole])
class PersonControllerSpec extends Specification {
@Shared
RestBuilder rest = new RestBuilder(connectTimeout:10000, readTimeout:20000)
@Shared
String baseUrl = "http://localhost:8080"
@Shared
int iterationCount = 0
Collection<Person> persons = []
def setup() {
Role adminRole = Role.findByAuthority("ROLE_ADMIN") ?: new Role(authority:"ROLE_ADMIN").save(failOnError:true, flush:true)
Role userRole = Role.findByAuthority("ROLE_USER") ?: new Role(authority:"ROLE_USER").save(failOnError:true, flush:true)
Person admin = new Person(name:"reserved", keyword:"admin", password:"password", email:"email@email.com", phone:"2222222222", personalPhoneNumber:"1112223333").save(failOnError:true, flush:true)
Person user = new Person(name:"reserved", keyword:"user", password:"password", email:"email@email.com", phone:"2222222222", personalPhoneNumber:"1112223333").save(failOnError:true, flush:true)
PersonRole.create(admin, adminRole, true)
PersonRole.create(user, userRole, true)
for (i in 0..20) {
persons << new Person(name:"person-$iterationCount-$i", password:"password", keyword:"p-$iterationCount-$i", email:"email@email.com", phone:"1112223333", personalPhoneNumber:"1112223333")
}
persons*.save(failOnError:true, flush:true)
}
def cleanup() { iterationCount++ }
void "test listing persons"() {
when: "we have an authenticated request"
JsonBuilder jsonBuilder = new JsonBuilder()
JSONObject json = jsonBuilder keyword:"admin", password: "password"
RestResponse authResponse = rest.post("$baseUrl/api/login") {
contentType "application/json"
body(json)
}
then: "can access both restricted and public resources"
...
}
}
の春のセキュリティ設定は次のConfig.groovy
とおりです。
grails.plugin.springsecurity.userLookup.userDomainClassName = 'com.help.Person'
grails.plugin.springsecurity.userLookup.usernamePropertyName = 'keyword'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'com.help.PersonRole'
grails.plugin.springsecurity.authority.className = 'com.help.Role'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
'/': ['permitAll'],
'/index': ['permitAll'],
'/index.gsp': ['permitAll'],
'/assets/**': ['permitAll'],
'/**/js/**': ['permitAll'],
'/**/css/**': ['permitAll'],
'/**/images/**': ['permitAll'],
'/**/favicon.ico': ['permitAll'],
'/dbconsole/**': ['ROLE_USER', 'ROLE_ADMIN']
]
grails.plugin.springsecurity.filterChain.chainMap = [
'/v1/public/**': 'anonymousAuthenticationFilter,restTokenValidationFilter,restExceptionTranslationFilter,filterInvocationInterceptor',
'/v1/**': 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter', // v1 rest api stateless
'/api/**': 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter', // api utility methods stateless
'/**': 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'
]
grails {
plugin {
springsecurity {
rest {
login.useJsonCredentials = true
login.usernamePropertyName = "keyword"
token {
rendering.usernamePropertyName = "keyword"
rendering.authoritiesPropertyName = "roles"
rendering.tokenPropertyName = "access_token"
validation.useBearerToken = true
validation.enableAnonymousAccess = true
}
}
}
}
}