user3629870
user3629870

Reputation: 43

JDBC Realm authentication bug Glassfish 4

Ok so I have spent a good amount of time on this but, it would appear that everything is set correctly and there is a bug in the com.sun.enterprise.security.ee.auth.realm.jdbc.JDBCRealm code.

I am attempting to use form based authentication with programmatic log in. I am using Glassfish 4 and JDK 1.8_40. When I enter my details into the login page the container attempts to direct me to the secured resource however it gives me a access denied at the same URL. Upon investigating this I have discovered that although the login succeeded the container failed to validate my login and has failed to associate the principle with any roles. This causing the access denied error. In order to discover what was going on I set the logging on glass fish to fine and discovered the array index out of bounds error seen in the stack trace.

[2015-03-25T16:19:43.088+0100] [glassfish 4.0] [FINE] [] [javax.enterprise.system.core.security.com.sun.enterprise.security.auth.realm] [tid: _ThreadID=59 _ThreadName=http-listener-1(4)] [timeMillis: 1427296783088] [levelValue: 500] [CLASSNAME: com.sun.enterprise.security.ee.auth.realm.jdbc.JDBCRealm] [METHODNAME: isUserValid] [[
  Cannot validate user
java.lang.ArrayIndexOutOfBoundsException: 64
    at com.sun.enterprise.security.ee.auth.realm.jdbc.JDBCRealm.isUserValid(JDBCRealm.java:430)
    at com.sun.enterprise.security.ee.auth.realm.jdbc.JDBCRealm.authenticate(JDBCRealm.java:324)
    at com.sun.enterprise.security.ee.auth.login.JDBCLoginModule.authenticate(JDBCLoginModule.java:78)
    at com.sun.enterprise.security.auth.login.PasswordLoginModule.authenticateUser(PasswordLoginModule.java:116)
    at com.sun.enterprise.security.BasePasswordLoginModule.login(BasePasswordLoginModule.java:146)
    at sun.reflect.GeneratedMethodAccessor78.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at javax.security.auth.login.LoginContext.invoke(LoginContext.java:755)
    at javax.security.auth.login.LoginContext.access$000(LoginContext.java:195)
    at javax.security.auth.login.LoginContext$4.run(LoginContext.java:682)
    at javax.security.auth.login.LoginContext$4.run(LoginContext.java:680)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
    at javax.security.auth.login.LoginContext.login(LoginContext.java:587)
    at com.sun.enterprise.security.auth.login.LoginContextDriver.doPasswordLogin(LoginContextDriver.java:383)
    at com.sun.enterprise.security.auth.login.LoginContextDriver.login(LoginContextDriver.java:241)
    at com.sun.enterprise.security.auth.login.LoginContextDriver.login(LoginContextDriver.java:154)
    at com.sun.web.security.RealmAdapter.authenticate(RealmAdapter.java:695)
    at com.sun.web.security.RealmAdapter.authenticate(RealmAdapter.java:636)
    at org.apache.catalina.authenticator.AuthenticatorBase.doLogin(AuthenticatorBase.java:957)
    at org.apache.catalina.authenticator.AuthenticatorBase.login(AuthenticatorBase.java:939)
    at org.apache.catalina.connector.Request.login(Request.java:2245)
    at org.apache.catalina.connector.Request.login(Request.java:2224)
    at org.apache.catalina.connector.RequestFacade.login(RequestFacade.java:1113)
    at com.merrimansa.beans.UserAuthBean.login(UserAuthBean.java:80)
    at com.merrimansa.beans.UserAuthBean$Proxy$_$$_WeldClientProxy.login(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at javax.el.ELUtil.invokeMethod(ELUtil.java:326)
    at javax.el.BeanELResolver.invoke(BeanELResolver.java:536)
    at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:256)
    at com.sun.el.parser.AstValue.invoke(AstValue.java:269)
    at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:304)
    at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
    at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
    at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
    at javax.faces.event.MethodExpressionActionListener.processAction(MethodExpressionActionListener.java:147)
    at javax.faces.event.ActionEvent.processListener(ActionEvent.java:88)
    at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:818)
    at javax.faces.component.UICommand.broadcast(UICommand.java:300)
    at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790)
    at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282)
    at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:646)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:318)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:357)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:188)
    at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191)
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168)
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189)
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838)
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544)
    at java.lang.Thread.run(Thread.java:745)
]]

[2015-03-25T16:19:43.150+0100] [glassfish 4.0] [FINE] [] [javax.enterprise.system.core.security] [tid: _ThreadID=33 _ThreadName=admin-listener(2)] [timeMillis: 1427296783150] [levelValue: 500] [CLASSNAME: com.sun.enterprise.security.web.integration.WebSecurityManager] [METHODNAME: setPolicyContext] [[
  [Web-Security] Policy Context ID was: __admingui/__admingui]]

[2015-03-25T16:19:43.151+0100] [glassfish 4.0] [FINE] [] [javax.enterprise.system.core.security] [tid: _ThreadID=33 _ThreadName=admin-listener(2)] [timeMillis: 1427296783151] [levelValue: 500] [CLASSNAME: com.sun.enterprise.security.web.integration.WebSecurityManager] [METHODNAME: checkPermissionWithoutCache] [[
  [Web-Security] Codesource with Web URL: file:/__admingui/__admingui]]

[2015-03-25T16:19:43.151+0100] [glassfish 4.0] [FINE] [] [javax.enterprise.system.core.security] [tid: _ThreadID=33 _ThreadName=admin-listener(2)] [timeMillis: 1427296783151] [levelValue: 500] [CLASSNAME: com.sun.enterprise.security.web.integration.WebSecurityManager] [METHODNAME: checkPermissionWithoutCache] [[
  [Web-Security] Checking Web Permission with Principals : null]]

[2015-03-25T16:19:43.151+0100] [glassfish 4.0] [FINE] [] [javax.enterprise.system.core.security] [tid: _ThreadID=33 _ThreadName=admin-listener(2)] [timeMillis: 1427296783151] [levelValue: 500] [CLASSNAME: com.sun.enterprise.security.web.integration.WebSecurityManager] [METHODNAME: checkPermissionWithoutCache] [[
  [Web-Security] Web Permission = ("javax.security.jacc.WebResourcePermission" "/download/log/" "GET")]]

[2015-03-25T16:19:43.151+0100] [glassfish 4.0] [FINE] [] [javax.enterprise.system.core.security.com.sun.enterprise.security.jmac.config] [tid: _ThreadID=33 _ThreadName=admin-listener(2)] [timeMillis: 1427296783151] [levelValue: 500] [CLASSNAME: com.sun.enterprise.security.jmac.config.GFServerConfigProvider] [METHODNAME: getEntry] [[
  getEntry for: HttpServlet -- GFConsoleAuthModule
    module class: org.glassfish.admingui.common.security.AdminConsoleAuthModule
    options: {loginErrorPage=/loginError.jsf, loginPage=/login.jsf}
    request policy: javax.security.auth.message.MessagePolicy@7a09d92
    response policy: null]]

[2015-03-25T16:19:43.182+0100] [glassfish 4.0] [FINE] [] [javax.enterprise.system.core.security.com.sun.enterprise.security.auth.realm] [tid: _ThreadID=252 _ThreadName=admin-listener(9)] [timeMillis: 1427296783182] [levelValue: 500] [CLASSNAME: com.sun.enterprise.security.auth.realm.file.FileRealm] [METHODNAME: init] [[
  FileRealm : file=/etc/Glassfish4/glassfish4/glassfish/domains/domain1/config/admin-keyfile]]

[2015-03-25T16:19:43.182+0100] [glassfish 4.0] [FINE] [] [javax.enterprise.system.core.security.com.sun.enterprise.security.auth.realm] [tid: _ThreadID=252 _ThreadName=admin-listener(9)] [timeMillis: 1427296783182] [levelValue: 500] [CLASSNAME: com.sun.enterprise.security.auth.realm.file.FileRealm] [METHODNAME: init] [[
  FileRealm : jaas-context=ignore]]

[2015-03-25T16:19:43.184+0100] [glassfish 4.0] [FINE] [] [javax.enterprise.system.core.security.com.sun.enterprise.security] [tid: _ThreadID=252 _ThreadName=admin-listener(9)] [timeMillis: 1427296783184] [levelValue: 500] [CLASSNAME: com.sun.enterprise.security.BasePasswordLoginModule] [METHODNAME: initialize] [[
  Login module initialized: class com.sun.enterprise.security.auth.login.FileLoginModule]]

[2015-03-25T16:19:43.184+0100] [glassfish 4.0] [FINE] [] [javax.enterprise.system.core.security.com.sun.enterprise.security] [tid: _ThreadID=252 _ThreadName=admin-listener(9)] [timeMillis: 1427296783184] [levelValue: 500] [CLASSNAME: com.sun.enterprise.security.BasePasswordLoginModule] [METHODNAME: abort] [[
  JAAS authentication aborted.]]

[2015-03-25T16:19:43.197+0100] [glassfish 4.0] [FINE] [] [javax.enterprise.system.core.security.com.sun.enterprise.security] [tid: _ThreadID=59 _ThreadName=http-listener-1(4)] [timeMillis: 1427296783197] [levelValue: 500] [CLASSNAME: com.sun.enterprise.security.BasePasswordLoginModule] [METHODNAME: login] [[
  JAAS login complete.]]

[2015-03-25T16:19:43.197+0100] [glassfish 4.0] [FINE] [] [javax.enterprise.system.core.security.com.sun.enterprise.security] [tid: _ThreadID=59 _ThreadName=http-listener-1(4)] [timeMillis: 1427296783197] [levelValue: 500] [CLASSNAME: com.sun.enterprise.security.BasePasswordLoginModule] [METHODNAME: commit] [[
  JAAS authentication committed.]]

[2015-03-25T16:19:43.198+0100] [glassfish 4.0] [FINE] [] [javax.enterprise.system.core.security.com.sun.enterprise.security.auth.login] [tid: _ThreadID=59 _ThreadName=http-listener-1(4)] [timeMillis: 1427296783198] [levelValue: 500] [CLASSNAME: com.sun.enterprise.security.auth.login.LoginContextDriver] [METHODNAME: doPasswordLogin] [[
  Password login succeeded for : [email protected]]]

[2015-03-25T16:19:43.207+0100] [glassfish 4.0] [FINE] [] [javax.enterprise.system.core.security.com.sun.enterprise.security.auth.login] [tid: _ThreadID=59 _ThreadName=http-listener-1(4)] [timeMillis: 1427296783207] [levelValue: 500] [CLASSNAME: com.sun.enterprise.security.auth.login.LoginContextDriver] [METHODNAME: doPasswordLogin] [[
  Set security context as user: [email protected]]]

[2015-03-25T16:19:43.467+0100] [glassfish 4.0] [FINE] [] [javax.enterprise.system.core.security] [tid: _ThreadID=56 _ThreadName=http-listener-1(1)] [timeMillis: 1427296783467] [levelValue: 500] [CLASSNAME: com.sun.enterprise.security.web.integration.WebSecurityManager] [METHODNAME: setPolicyContext] [[
  [Web-Security] Setting Policy Context ID: old = null ctxID = HSEManagmentApp/HSEManagmentApp]]

I then investigated the source code for the method in question and discovered a comment saying it could accept a maximum length of 50 see code below. I'm not sure if this is a red herring or if I have just set something wrong in my JDBC realm. Any help on this would be much appreciated as it is eating up my time and I'm no closer to a solution.

private boolean isUserValid(String user, char[] password) {
401        Connection connection = null;
402        PreparedStatement statement = null;
403        ResultSet rs = null;
404        boolean valid = false;
405
406        try {
407            char[] hpwd = hashPassword(password);
408            connection = getConnection();
409            statement =  connection.prepareStatement(passwordQuery);
410            statement.setString(1, user);
411            rs = statement.executeQuery();
412            if (rs.next()) {
413                //Obtain the password as a char[] with a  max size of 50
414                Reader reader =  rs.getCharacterStream(1);
415                char[] pwd = new char[1024];
416                int noOfChars = reader.read(pwd);
417
418                /*Since pwd contains 1024 elements arbitrarily initialized,
419                    construct a new char[] that has the right no of char elements
420                    to be used for equal comparison*/
421                if (noOfChars < 0) {
422                    noOfChars = 0;
423                }
424                char[] passwd = new char[noOfChars];
425                System.arraycopy(pwd, 0, passwd, 0, noOfChars);
426                if (HEX.equalsIgnoreCase(getProperty(PARAM_ENCODING))) {
427                    valid = true;
428                    //Do a case-insensitive equals
429                    for(int i = 0; i < noOfChars; i ++) {
430                        if (!(Character.toLowerCase(passwd[i]) == Character.toLowerCase(hpwd[i]))) {
431                            valid = false;
432                            break;
433                        }
434                    }
435                } else {
436                    valid = Arrays.equals(passwd, hpwd);
437                }
438            }
439        } catch(SQLException ex) {
440                _logger.log(Level.SEVERE, "jdbcrealm.invaliduserreason", 
441                        new String [] {user,ex.toString()});
442            if (_logger.isLoggable(Level.FINE)) {
443                _logger.log(Level.FINE, "Cannot validate user", ex);
444            } 
445        } catch(Exception ex) {
446            _logger.log(Level.SEVERE, "jdbcrealm.invaliduser", user);
447            if (_logger.isLoggable(Level.FINE)) {
448                _logger.log(Level.FINE, "Cannot validate user", ex);
449            }
450        } finally {
451            close(connection, statement, rs);
452        }
453        return valid;
454    }

I have attached my realm file in case it is something silly but I have tried just about every combination. I have also checked my hashing in the database and it is correct. Only odd thing is if I set hashing to 'none' then it doesn't work at all.

Upvotes: 0

Views: 1270

Answers (1)

user3629870
user3629870

Reputation: 43

Ok I have solved this issue and all the others I was having with authentication and wanted to post an answer for future people facing this problem. It seems that the SQL queries being used are filling in any unused space in the database field with white space so; as I had my password field set to nvarchar(500) that was the length of the password that was being returned although all characters after 64 were white space. This also caused an issue with role to group mapping, as this is a various length field I cant change the field length to compensate so must now look for the problem with the driver or queries involved.

Regards

Upvotes: 1

Related Questions