mitreid-connect / OpenID-Connect-Java-Spring-Server

An OpenID Connect reference implementation in Java on the Spring platform.
Other
1.48k stars 765 forks source link

AuthenticationHolderEntity.extensions null value causes NullPointerException from map.put("external_launch_required", null) on query. #1394

Open lwedmo opened 6 years ago

lwedmo commented 6 years ago

I'm using version 1.3.2. Sometimes when I perform the delegation request I get a null pointer exception. Looking into it, I see that The code is reading a record from the auth_holder_extension table, in which the values are {extension: "external_launch_required"; val: null}.

I see that AuthenticationHolderEntity.extensions is mapped as a Collection table. This is JPA's eager fetch of AuthenticationHolderEntity.extensions. I think this means that database column authentication_holder_extension.val should be constrained as not null. To represent a null value in the map, we would omit the value. Maybe somewhere upstream, we can choose to omit null valued extension key value pairs.

Stepping back a bit, the use case where this comes up is where there is no launch context. I would like to learn more about how external launch works. Does the server try to fetch it from somewhere?

Here's a stack trace. Thread [default task-28] (Suspended (exception NullPointerException))
owns: Hashtable<K,V> (id=572)
Hashtable<K,V>.put(K, V) line: not available
MappedKeyMapContainerPolicy(MapContainerPolicy).addInto(Object, Object, Object, AbstractSession) line: 131
MappedKeyMapContainerPolicy.addInto(Object, Object, AbstractSession, AbstractRecord, DataReadQuery, CacheKey, boolean) line: 196
DataReadQuery.executeNonCursor() line: 226
DataReadQuery.executeDatabaseQuery() line: 152
DataReadQuery(DatabaseQuery).execute(AbstractSession, AbstractRecord) line: 899 DataReadQuery.execute(AbstractSession, AbstractRecord) line: 137
DataReadQuery(DatabaseQuery).executeInUnitOfWork(UnitOfWorkImpl, AbstractRecord) line: 798
RepeatableWriteUnitOfWork(UnitOfWorkImpl).internalExecuteQuery(DatabaseQuery, AbstractRecord) line: 2896
RepeatableWriteUnitOfWork(AbstractSession).executeQuery(DatabaseQuery, AbstractRecord, int) line: 1793
RepeatableWriteUnitOfWork(AbstractSession).executeQuery(DatabaseQuery, AbstractRecord) line: 1775
NoIndirectionPolicy.valueFromQuery(ReadQuery, AbstractRecord, AbstractSession) line: 326
DirectMapMapping(DirectCollectionMapping).valueFromRow(AbstractRecord, JoinedAttributeManager, ObjectBuildingQuery, CacheKey, AbstractSession, boolean, Boolean[]) line: 3164
DirectMapMapping(ForeignReferenceMapping).buildCloneFromRow(AbstractRecord, JoinedAttributeManager, Object, CacheKey, ObjectBuildingQuery, UnitOfWorkImpl, AbstractSession) line: 336
ObjectBuilder.buildAttributesIntoWorkingCopyClone(Object, CacheKey, ObjectBuildingQuery, JoinedAttributeManager, AbstractRecord, UnitOfWorkImpl, boolean) line: 1996
ObjectBuilder.buildWorkingCopyCloneFromRow(ObjectBuildingQuery, JoinedAttributeManager, AbstractRecord, UnitOfWorkImpl, Object, CacheKey) line: 2249
ObjectBuilder.buildObjectInUnitOfWork(ObjectBuildingQuery, JoinedAttributeManager, AbstractRecord, UnitOfWorkImpl, Object, CacheKey, ClassDescriptor) line: 847 ObjectBuilder.buildObject(ObjectBuildingQuery, AbstractRecord, JoinedAttributeManager, AbstractSession, ClassDescriptor, InheritancePolicy, boolean, boolean, boolean) line: 734
ObjectBuilder.buildObject(ObjectBuildingQuery, AbstractRecord, JoinedAttributeManager) line: 688
ReadObjectQuery(ObjectLevelReadQuery).buildObject(AbstractRecord) line: 795 ReadObjectQuery.registerResultInUnitOfWork(Object, UnitOfWorkImpl, AbstractRecord, boolean) line: 885
ReadObjectQuery.executeObjectLevelReadQuery() line: 552 ReadObjectQuery(ObjectLevelReadQuery).executeDatabaseQuery() line: 1168 ReadObjectQuery(DatabaseQuery).execute(AbstractSession, AbstractRecord) line: 899
ReadObjectQuery(ObjectLevelReadQuery).execute(AbstractSession, AbstractRecord) line: 1127
ReadObjectQuery.execute(AbstractSession, AbstractRecord) line: 431
ReadObjectQuery(ObjectLevelReadQuery).executeInUnitOfWork(UnitOfWorkImpl, AbstractRecord) line: 1215
RepeatableWriteUnitOfWork(UnitOfWorkImpl).internalExecuteQuery(DatabaseQuery, AbstractRecord) line: 2896
RepeatableWriteUnitOfWork(AbstractSession).executeQuery(DatabaseQuery, AbstractRecord, int) line: 1793
RepeatableWriteUnitOfWork(AbstractSession).executeQuery(DatabaseQuery, AbstractRecord) line: 1775
NoIndirectionPolicy.valueFromQuery(ReadQuery, AbstractRecord, AbstractSession) line: 326
ManyToOneMapping(ForeignReferenceMapping).valueFromRowInternal(AbstractRecord, JoinedAttributeManager, ObjectBuildingQuery, AbstractSession, boolean) line: 2294
ManyToOneMapping(OneToOneMapping).valueFromRowInternal(AbstractRecord, JoinedAttributeManager, ObjectBuildingQuery, AbstractSession, boolean) line: 1795
ManyToOneMapping(ForeignReferenceMapping).valueFromRow(AbstractRecord, JoinedAttributeManager, ObjectBuildingQuery, CacheKey, AbstractSession, boolean, Boolean[]) line: 2144
ManyToOneMapping(ForeignReferenceMapping).buildCloneFromRow(AbstractRecord, JoinedAttributeManager, Object, CacheKey, ObjectBuildingQuery, UnitOfWorkImpl, AbstractSession) line: 336
ObjectBuilder.buildAttributesIntoWorkingCopyClone(Object, CacheKey, ObjectBuildingQuery, JoinedAttributeManager, AbstractRecord, UnitOfWorkImpl, boolean) line: 1996
ObjectBuilder.buildWorkingCopyCloneFromRow(ObjectBuildingQuery, JoinedAttributeManager, AbstractRecord, UnitOfWorkImpl, Object, CacheKey) line: 2249
ObjectBuilder.buildObjectInUnitOfWork(ObjectBuildingQuery, JoinedAttributeManager, AbstractRecord, UnitOfWorkImpl, Object, CacheKey, ClassDescriptor) line: 847 ObjectBuilder.buildObject(ObjectBuildingQuery, AbstractRecord, JoinedAttributeManager, AbstractSession, ClassDescriptor, InheritancePolicy, boolean, boolean, boolean) line: 734
ObjectBuilder.buildObject(ObjectBuildingQuery, AbstractRecord, JoinedAttributeManager) line: 688
ReadAllQuery(ObjectLevelReadQuery).buildObject(AbstractRecord) line: 795
ReadAllQuery.registerResultInUnitOfWork(Object, UnitOfWorkImpl, AbstractRecord, boolean) line: 890
ReadAllQuery.executeObjectLevelReadQuery() line: 509
ReadAllQuery(ObjectLevelReadQuery).executeDatabaseQuery() line: 1168
ReadAllQuery(DatabaseQuery).execute(AbstractSession, AbstractRecord) line: 899
ReadAllQuery(ObjectLevelReadQuery).execute(AbstractSession, AbstractRecord) line: 1127
ReadAllQuery.execute(AbstractSession, AbstractRecord) line: 403 ReadAllQuery(ObjectLevelReadQuery).executeInUnitOfWork(UnitOfWorkImpl, AbstractRecord) line: 1215
RepeatableWriteUnitOfWork(UnitOfWorkImpl).internalExecuteQuery(DatabaseQuery, AbstractRecord) line: 2896
RepeatableWriteUnitOfWork(AbstractSession).executeQuery(DatabaseQuery, AbstractRecord, int) line: 1793
RepeatableWriteUnitOfWork(AbstractSession).executeQuery(DatabaseQuery, AbstractRecord) line: 1775
RepeatableWriteUnitOfWork(AbstractSession).executeQuery(DatabaseQuery, List) line: 1740 EJBQueryImpl(QueryImpl).executeReadQuery() line: 258 EJBQueryImpl(QueryImpl).getResultList() line: 469
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: not available
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: not available
Method.invoke(Object, Object...) line: not available
SharedEntityManagerCreator$DeferredQueryInvocationHandler.invoke(Object, Method, Object[]) line: 372
$Proxy88.getResultList() line: not available
JpaOAuth2TokenRepository.getAccessTokenByValue(String) line: 81 JpaOAuth2TokenRepository$$FastClassBySpringCGLIB$$145026dd.invoke(int, Object, Object[]) line: not available
MethodProxy.invoke(Object, Object[]) line: 204
CglibAopProxy$DynamicAdvisedInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 652
JpaOAuth2TokenRepository$$EnhancerBySpringCGLIB$$16843ebc.getAccessTokenByValue(String) line: not available DefaultOAuth2ProviderTokenService.readAccessToken(String) line: 434 DefaultOAuth2ProviderTokenService$$FastClassBySpringCGLIB$$552a06ba.invoke(int, Object, Object[]) line: not available
MethodProxy.invoke(Object, Object[]) line: 204
CglibAopProxy$DynamicAdvisedInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 652
DefaultOAuth2ProviderTokenService$$EnhancerBySpringCGLIB$$11fa3073.readAccessToken(String) line: not available
ChainedTokenGranter.getOAuth2Authentication(ClientDetails, TokenRequest) line: 72
ChainedTokenGranter(AbstractTokenGranter).getAccessToken(ClientDetails, TokenRequest) line: 70
ChainedTokenGranter(AbstractTokenGranter).grant(String, TokenRequest) line: 65
CompositeTokenGranter.grant(String, TokenRequest) line: 38
TokenEndpoint.postAccessToken(Principal, Map<String,String>) line: 132
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: not available
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: not available
Method.invoke(Object, Object...) line: not available
ServletInvocableHandlerMethod(InvocableHandlerMethod).doInvoke(Object...) line: 205 ServletInvocableHandlerMethod(InvocableHandlerMethod).invokeForRequest(NativeWebRequest, ModelAndViewContainer, Object...) line: 133
ServletInvocableHandlerMethod.invokeAndHandle(ServletWebRequest, ModelAndViewContainer, Object...) line: 116
RequestMappingHandlerAdapter.invokeHandlerMethod(HttpServletRequest, HttpServletResponse, HandlerMethod) line: 827
RequestMappingHandlerAdapter.handleInternal(HttpServletRequest, HttpServletResponse, HandlerMethod) line: 738
RequestMappingHandlerAdapter(AbstractHandlerMethodAdapter).handle(HttpServletRequest, HttpServletResponse, Object) line: 85 DispatcherServlet.doDispatch(HttpServletRequest, HttpServletResponse) line: 963 DispatcherServlet.doService(HttpServletRequest, HttpServletResponse) line: 897
DispatcherServlet(FrameworkServlet).processRequest(HttpServletRequest, HttpServletResponse) line: 970
DispatcherServlet(FrameworkServlet).doPost(HttpServletRequest, HttpServletResponse) line: 872
DispatcherServlet(HttpServlet).service(HttpServletRequest, HttpServletResponse) line: 707
DispatcherServlet(FrameworkServlet).service(HttpServletRequest, HttpServletResponse) line: 846
DispatcherServlet(HttpServlet).service(ServletRequest, ServletResponse) line: 790
ServletHandler.handleRequest(HttpServerExchange) line: 85
FilterHandler$FilterChainImpl.doFilter(ServletRequest, ServletResponse) line: 129
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 317 FilterSecurityInterceptor.invoke(FilterInvocation) line: 127
FilterSecurityInterceptor.doFilter(ServletRequest, ServletResponse, FilterChain) line: 91
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331 ExceptionTranslationFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 114 FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331 AnonymousAuthenticationFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 111
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331 SecurityContextHolderAwareRequestFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 170
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331 ClientCredentialsTokenEndpointFilter.successfulAuthentication(HttpServletRequest, HttpServletResponse, FilterChain, Authentication) line: 131
ClientCredentialsTokenEndpointFilter(AbstractAuthenticationProcessingFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 240
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331 BasicAuthenticationFilter.doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) line: 158
BasicAuthenticationFilter(OncePerRequestFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 107
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331 JWTBearerClientAssertionTokenEndpointFilter(AbstractAuthenticationProcessingFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 200
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331 HeaderWriterFilter.doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) line: 64
HeaderWriterFilter(OncePerRequestFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 107
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331 WebAsyncManagerIntegrationFilter.doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) line: 56
WebAsyncManagerIntegrationFilter(OncePerRequestFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 107 FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331 CorsFilter.doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) line: 57
CorsFilter(OncePerRequestFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 107
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331 SecurityContextPersistenceFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 105
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331 FilterChainProxy.doFilterInternal(ServletRequest, ServletResponse, FilterChain) line: 214
FilterChainProxy.doFilter(ServletRequest, ServletResponse, FilterChain) line: 177
DelegatingFilterProxy.invokeDelegate(Filter, ServletRequest, ServletResponse, FilterChain) line: 346
DelegatingFilterProxy.doFilter(ServletRequest, ServletResponse, FilterChain) line: 262
ManagedFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 61
FilterHandler$FilterChainImpl.doFilter(ServletRequest, ServletResponse) line: 131
FilterHandler.handleRequest(HttpServerExchange) line: 84
ServletSecurityRoleHandler.handleRequest(HttpServerExchange) line: 62
ServletDispatchingHandler.handleRequest(HttpServerExchange) line: 36
SecurityContextAssociationHandler.handleRequest(HttpServerExchange) line: 78
PredicateHandler.handleRequest(HttpServerExchange) line: 43 SSLInformationAssociationHandler.handleRequest(HttpServerExchange) line: 131
ServletAuthenticationCallHandler.handleRequest(HttpServerExchange) line: 57 PredicateHandler.handleRequest(HttpServerExchange) line: 43 ServletConfidentialityConstraintHandler(AbstractConfidentialityHandler).handleRequest(HttpServerExchange) line: 46
ServletConfidentialityConstraintHandler.handleRequest(HttpServerExchange) line: 64
AuthenticationMechanismsHandler.handleRequest(HttpServerExchange) line: 60
CachedAuthenticatedSessionHandler.handleRequest(HttpServerExchange) line: 77
NotificationReceiverHandler.handleRequest(HttpServerExchange) line: 50
SecurityInitialHandler(AbstractSecurityContextAssociationHandler).handleRequest(HttpServerExchange) line: 43
PredicateHandler.handleRequest(HttpServerExchange) line: 43 JACCContextIdHandler.handleRequest(HttpServerExchange) line: 61 PredicateHandler.handleRequest(HttpServerExchange) line: 43 PredicateHandler.handleRequest(HttpServerExchange) line: 43 ServletInitialHandler.handleFirstRequest(HttpServerExchange, ServletRequestContext) line: 292
ServletInitialHandler.access$100(ServletInitialHandler, HttpServerExchange, ServletRequestContext) line: 81 ServletInitialHandler$2.call(HttpServerExchange, ServletRequestContext) line: 138
ServletInitialHandler$2.call(HttpServerExchange, Object) line: 135
ServletRequestContextThreadSetupAction$1.call(HttpServerExchange, C) line: 48
ContextClassLoaderSetupAction$1.call(HttpServerExchange, C) line: 43
LegacyThreadSetupActionWrapper$1.call(HttpServerExchange, C) line: 44
LegacyThreadSetupActionWrapper$1.call(HttpServerExchange, C) line: 44
LegacyThreadSetupActionWrapper$1.call(HttpServerExchange, C) line: 44
LegacyThreadSetupActionWrapper$1.call(HttpServerExchange, C) line: 44
LegacyThreadSetupActionWrapper$1.call(HttpServerExchange, C) line: 44
LegacyThreadSetupActionWrapper$1.call(HttpServerExchange, C) line: 44
ServletInitialHandler.dispatchRequest(HttpServerExchange, ServletRequestContext, ServletChain, DispatcherType) line: 272
ServletInitialHandler.access$000(ServletInitialHandler, HttpServerExchange, ServletRequestContext, ServletChain, DispatcherType) line: 81
ServletInitialHandler$1.handleRequest(HttpServerExchange) line: 104 Connectors.executeRootHandler(HttpHandler, HttpServerExchange) line: 202
HttpServerExchange$1.run() line: 805
XnioWorker$TaskPool(ThreadPoolExecutor).runWorker(ThreadPoolExecutor$Worker) line: not available
ThreadPoolExecutor$Worker.run() line: not available Thread.run() line: not available

jricher commented 6 years ago

Launch contexts are something added by the SMART server, which is a customization of this project. The constraint you mention can probably be added to this (the upstream project) but you should report this to the SMART project.

lwedmo commented 6 years ago

OK, I'll look into the SMART project. And in the mean time, I committed a change to AuthenticationHolderEntity, a bit of bullet proofing to filter null values from the map, essentially storing a null value as missing from the map. This will avoid creating data in future which causes NPE.

jricher commented 6 years ago

Feel free to submit your change as a pull request to this project and we'll review it.

euz1e4r commented 6 years ago

Caution: I'm a long time Perforce user on a git learning curve. This will be my first pull request. I have two github identities, work (euz1e4r) and personal(lwedmo). I submitted this issue under my personal and may have committed my change on the master branch under work identity. I'm going to see if I can create and push a branch. Maybe my commit needs to be undone. Trying. With lot of help from Tun, I got the pull request in, using SourceTree. My take-away is that git pull requests happen across repositories, not within the same repository. I'm used to thinking of single, central repository from Perforce world view.