2

I'm using Grails 3.1.4 with spring-security-rest plugin. Usually everthing works fine, but when one of our test users tries to fetch any data from a controller the server's cpu usage climbs up to 100% followed by a java.lang.outofmemory error.

I don't understand why the request work for other user accounts except his. Maybe it's about his name which contains an á character.

Update 8.4.16

It's not user account specific! But we noticed that this error only occurs for our client application on iOS 9.3 and later.

Debugging this error is kind of annoying and I don't have a clue how to resolve this issue.

Is there anyone who might provide a hint?

2016-03-26 20:42:20,476 ERROR http-bio-8443-exec-120  org.springframework.boot.context.web.ErrorPageFilter - Forwarding to error page from request [/users/2] due to exception [GC overhead limit exceeded]
java.lang.OutOfMemoryError: GC overhead limit exceeded
    at grails.views.ResolvableGroovyTemplateEngine.resolveTemplate(ResolvableGroovyTemplateEngine.groovy:297)
    at grails.views.mvc.GenericGroovyTemplateView.renderMergedOutputModel(GenericGroovyTemplateView.groovy:52)
    at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
    at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1243)
    at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1027)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:971)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:969)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:860)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:845)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at javax.servlet.FilterChain$doFilter.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at javax.servlet.FilterChain$doFilter$0.call(Unknown Source)
    at grails.plugin.springsecurity.rest.RestAuthenticationFilter.doFilter(RestAuthenticationFilter.groovy:143)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at javax.servlet.FilterChain$doFilter.call(Unknown Source)
    at grails.plugin.springsecurity.rest.RestLogoutFilter.doFilter(RestLogoutFilter.groovy:80)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at javax.servlet.FilterChain$doFilter.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)

UserController.groovy

@Secured('ROLE_ADMIN')
class UserController extends RestfulController {
    static responseFormats = ['json', 'xml']
    UserController() {
        super(User)
    }
    SpringSecurityService springSecurityService

    @Secured('ROLE_USER')
    def show() {
        def authenticatedUser = springSecurityService.currentUser
        User user = User.findById(params.long('id'))
        if (user == null) {
            render(message: 'User not found', status: 404)
        } else if (user != authenticatedUser){
            render(message: 'not authorized', status: 401)
        } else if (user == authenticatedUser){
            respond user
        } else {
            render status: 404
        }
    }
}

build.gradle

dependencies {
    ...
    compile "org.grails.plugins:spring-security-rest:2.0.0.M2"
    ...
}

application.groovy

grails.plugin.springsecurity.filterChain.chainMap = [
        //Stateless chain
        [
                pattern: '/**',
                filters: 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter'
        ],

        //Traditional, stateful chain
        [
                pattern: '/stateful/**',
                filters: 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'
        ]
]


// Added by the Spring Security Core plugin:
grails.plugin.springsecurity.userLookup.userDomainClassName = 'net.connactivities.api.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'net.connactivities.api.UserRole'
grails.plugin.springsecurity.authority.className = 'net.connactivities.api.Role'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
    [pattern: '/',               access: ['permitAll']],
    [pattern: '/error',          access: ['permitAll']],
    [pattern: '/index',          access: ['permitAll']],
    [pattern: '/index.gsp',      access: ['permitAll']],
    [pattern: '/shutdown',       access: ['permitAll']],
    [pattern: '/assets/**',      access: ['permitAll']],
    [pattern: '/**/js/**',       access: ['permitAll']],
    [pattern: '/**/css/**',      access: ['permitAll']],
    [pattern: '/**/images/**',   access: ['permitAll']],
    [pattern: '/**/favicon.ico', access: ['permitAll']]
]

grails.plugin.springsecurity.filterChain.chainMap = [
    [pattern: '/assets/**',      filters: 'none'],
    [pattern: '/**/js/**',       filters: 'none'],
    [pattern: '/**/css/**',      filters: 'none'],
    [pattern: '/**/images/**',   filters: 'none'],
    [pattern: '/**/favicon.ico', filters: 'none'],
    [pattern: '/**',             filters: 'JOINED_FILTERS']
]

RequestHandler.swift

...
let session = NSURLSession()

func performHTTPRequest(url: String, method: String, withParameters params: [String:AnyObject]?, useAuth: Bool = true, andCompletionBlock completionBlock: (success:Bool, data: NSData?)-> ()) {

   let myURL = NSURL(string: url)
   let request = NSMutableURLRequest(URL:myURL!)

   // HTTP Method
   request.HTTPMethod = method

   // Include Header options
   request.addValue("application/json", forHTTPHeaderField: "Content-Type")
   request.addValue("application/json", forHTTPHeaderField: "Accept")

   do {
       if params != nil {
           let body = try NSJSONSerialization.dataWithJSONObject(params!, options: .PrettyPrinted)
           request.HTTPBody = body
       }
   } catch _ {
       // Error handling
       return
   }

   if useAuth {
       if let auth = authorization() {
           request.setValue("Bearer " + auth, forHTTPHeaderField: "Authorization")
       }
   }

   let task = session.dataTaskWithRequest(request) {
       data, response, error in

       if error != nil {
           // Error handling
           return
       }

       let statusCode = (response as! NSHTTPURLResponse).statusCode

       if statusCode.isNotAcceptedHTTPCode() {
           // HTTP Error
       }
       else {
           if data?.length != 0 {
               // OK
           }

           else {
               // Empty data
           }
       }
   }

   task.resume()
}
...
feuernurmitm
  • 312
  • 2
  • 11
  • What request are they making? – tim_yates Apr 02 '16 at 18:13
  • @tim_yates first they do a `POST /api/login` with their username and password to obtain their bearer access token. This is working fine. But then at the next authorized request eg. `GET /users/2` with header parameter `Authorization: Bearer XXXXX...` the error occurs. As mentioned above this is only happening with this specific user account. All users use the same client version. – feuernurmitm Apr 03 '16 at 00:37
  • @Fmeuer can you try creating another dummy user creating a similar name? I also faced a similar issue but with grails test-app command and I don't exactly remember what was causing this. Does this issue appear in production only? – Ejaz Ahmed Apr 04 '16 at 11:51
  • @EjazAhmed We noticed that it is not the characters in the user's name which cause the error. But it seems to occur only on iOS 9.3 and later as api client. Error appears in production and development... – feuernurmitm Apr 08 '16 at 12:02
  • You should debug iOS client code and analyze its pattern being sent to server. Then post a separate question under iOS tag. It will be even beneficial if you link your new question to this one. – Ejaz Ahmed Apr 08 '16 at 12:14
  • Thanks for your suggestions. For now we went back to Grails 2.5.1 which was working fine. We are spending too much time on debugging this error... – feuernurmitm Apr 12 '16 at 14:01

0 Answers0