AttributeDescriptor { Object readReflection(Object target, ExecutionContext executionContext) throws NameNotFoundException, QueryInvocationTargetException { Support.Assert(target != null); Support.Assert(target != QueryService.UNDEFINED); if (target instanceof Token) { return QueryService.UNDEFINED; } Class resolutionClass = target.getClass(); Member m = getReadMember(resolutionClass); try { if (m instanceof Method) { try { Method method = (Method) m; MethodInvocationAuthorizer authorizer = executionContext.getMethodInvocationAuthorizer(); if (executionContext.isCqQueryContext()) { if (!authorizer.authorize(method, target)) { throw new NotAuthorizedException(UNAUTHORIZED_STRING + method.getName()); } } else { boolean authorizationResult; Boolean cachedResult = (Boolean) executionContext.cacheGet(method); if (cachedResult == null) { authorizationResult = authorizer.authorize(method, target); executionContext.cachePut(method, authorizationResult); } else { authorizationResult = cachedResult; } if (!authorizationResult) { throw new NotAuthorizedException(UNAUTHORIZED_STRING + method.getName()); } } return method.invoke(target, (Object[]) null); } catch (EntryDestroyedException e) { return QueryService.UNDEFINED; } catch (IllegalAccessException e) { throw new NameNotFoundException( String.format( "Method ' %s ' in class ' %s ' is not accessible to the query processor", m.getName(), target.getClass().getName()), e); } catch (InvocationTargetException e) { Throwable t = e.getTargetException(); if ((t instanceof EntryDestroyedException)) { return QueryService.UNDEFINED; } if (t instanceof Exception) throw new QueryInvocationTargetException(t); throw new QueryInvocationTargetException(e); } } else { try { return ((Field) m).get(target); } catch (IllegalAccessException e) { throw new NameNotFoundException( String.format( "Field ' %s ' in class ' %s ' is not accessible to the query processor", m.getName(), target.getClass().getName()), e); } catch (EntryDestroyedException e) { return QueryService.UNDEFINED; } } } catch (EntryDestroyedException e) { return QueryService.UNDEFINED; } } AttributeDescriptor(TypeRegistry pdxRegistry, String name); boolean validateReadType(Class targetType); Object read(Object target, ExecutionContext executionContext);  }
@Test public void readReflectionShouldReturnUndefinedWhenTargetObjectIsAnInternalToken() throws NameNotFoundException, QueryInvocationTargetException { AttributeDescriptor attributeDescriptor = new AttributeDescriptor(typeRegistry, "nonExistingAttribute"); assertThat(attributeDescriptor.readReflection(mock(Token.class), queryExecutionContext)) .isEqualTo(QueryService.UNDEFINED); }
@Test public void readReflectionShouldThrowExceptionWhenMemberCanNotBeFound() { AttributeDescriptor attributeDescriptor = new AttributeDescriptor(typeRegistry, "nonExistingAttribute"); assertThatThrownBy( () -> attributeDescriptor.readReflection(TestBean.class, queryExecutionContext)) .isInstanceOf(NameNotFoundException.class); }
@Test public void readReflectionShouldReturnUndefinedWhenEntryDestroyedExceptionIsThrown() throws NameNotFoundException, QueryInvocationTargetException { doReturn(true).when(methodInvocationAuthorizer).authorize(any(), any()); AttributeDescriptor attributeDescriptor = spy(new AttributeDescriptor(typeRegistry, "throwEntryDestroyedExceptionMethod")); assertThat(attributeDescriptor.readReflection(testBean, queryExecutionContext)) .isEqualTo(QueryService.UNDEFINED); }
@Test @Parameters({PUBLIC_NO_ACCESSORS, PUBLIC_ACCESSOR_BY_NAME, PUBLIC_ACCESSOR_BY_GETTER}) public void readReflectionForPublicAttributeShouldNotInvokeAuthorizer(String attributeName) throws NameResolutionException, QueryInvocationTargetException { AttributeDescriptor attributeDescriptor = new AttributeDescriptor(typeRegistry, attributeName); Object result = attributeDescriptor.readReflection(testBean, queryExecutionContext); assertThat(result).isInstanceOf(String.class); assertThat(result).isEqualTo(attributeName); verify(methodInvocationAuthorizer, never()).authorize(any(), any()); }
@Test @Parameters({PRIVATE_ACCESSOR_BY_NAME, PRIVATE_ACCESSOR_BY_GETTER}) public void readReflectionForImplicitMethodInvocationShouldReturnCorrectlyWhenMethodIsAuthorized( String attributeName) throws NameResolutionException, QueryInvocationTargetException { doReturn(true).when(methodInvocationAuthorizer).authorize(any(), any()); AttributeDescriptor attributeDescriptor = new AttributeDescriptor(typeRegistry, attributeName); Object result = attributeDescriptor.readReflection(testBean, queryExecutionContext); assertThat(result).isInstanceOf(String.class); assertThat(result).isEqualTo(attributeName); }
@Test @Parameters({ "nonPublicAttributeWithPublicAccessor, nonPublicAttributeWithPublicAccessor", "nonPublicAttributeWithPublicGetterMethod, getNonPublicAttributeWithPublicGetterMethod"}) public void readReflectionForImplicitMethodInvocationShouldReturnCorrectlyWhenMethodIsAuthorizedAndCacheResult( String attributeName, String methodName) throws Exception { doReturn(true).when(methodInvocationAuthorizer).authorize(any(), any()); AttributeDescriptor attributeDescriptor = new AttributeDescriptor(typeRegistry, attributeName); attributeDescriptor.readReflection(testBean, queryExecutionContext); Method method = TestBean.class.getMethod(methodName); assertThat(queryExecutionContext.cacheGet(method)).isEqualTo(true); }
@Test @Parameters({ "nonPublicAttributeWithPublicAccessor, nonPublicAttributeWithPublicAccessor", "nonPublicAttributeWithPublicGetterMethod, getNonPublicAttributeWithPublicGetterMethod"}) public void readReflectionForImplicitMethodInvocationShouldReturnCorrectlyWhenMethodIsAuthorizedAndDoNotCacheResultForCqs( String attributeName, String methodName) throws Exception { when(queryExecutionContext.isCqQueryContext()).thenReturn(true); doReturn(true).when(methodInvocationAuthorizer).authorize(any(), any()); AttributeDescriptor attributeDescriptor = new AttributeDescriptor(typeRegistry, attributeName); attributeDescriptor.readReflection(testBean, queryExecutionContext); Method method = TestBean.class.getMethod(methodName); assertThat(queryExecutionContext.cacheGet(method)).isNull(); }
@Test public void readReflectionForImplicitMethodInvocationShouldUseCachedAuthorizerResultWhenMethodIsAuthorizedAndQueryContextIsTheSame() { doReturn(true).when(methodInvocationAuthorizer).authorize(any(), any()); AttributeDescriptor nonPublicAttributeWithPublicAccessor = new AttributeDescriptor(typeRegistry, PRIVATE_ACCESSOR_BY_NAME); AttributeDescriptor nonPublicAttributeWithPublicGetterMethod = new AttributeDescriptor(typeRegistry, PRIVATE_ACCESSOR_BY_GETTER); IntStream.range(0, 10).forEach(element -> { try { assertThat( nonPublicAttributeWithPublicAccessor.readReflection(testBean, queryExecutionContext)) .isInstanceOf(String.class).isEqualTo(PRIVATE_ACCESSOR_BY_NAME); assertThat(nonPublicAttributeWithPublicGetterMethod.readReflection(testBean, queryExecutionContext)).isInstanceOf(String.class) .isEqualTo(PRIVATE_ACCESSOR_BY_GETTER); } catch (NameNotFoundException | QueryInvocationTargetException exception) { throw new RuntimeException(exception); } }); verify(methodInvocationAuthorizer, times(2)).authorize(any(), any()); }
@Test public void readReflectionForImplicitMethodInvocationShouldNotUseCachedAuthorizerResultWhenMethodIsAuthorizedAndQueryContextIsNotTheSame() { doReturn(true).when(methodInvocationAuthorizer).authorize(any(), any()); AttributeDescriptor nonPublicAttributeWithPublicAccessor = new AttributeDescriptor(typeRegistry, PRIVATE_ACCESSOR_BY_NAME); AttributeDescriptor nonPublicAttributeWithPublicGetterMethod = new AttributeDescriptor(typeRegistry, PRIVATE_ACCESSOR_BY_GETTER); IntStream.range(0, 10).forEach(element -> { try { QueryExecutionContext mockContext = mock(QueryExecutionContext.class); when(mockContext.getMethodInvocationAuthorizer()).thenReturn(methodInvocationAuthorizer); assertThat(nonPublicAttributeWithPublicAccessor.readReflection(testBean, mockContext)) .isInstanceOf(String.class).isEqualTo(PRIVATE_ACCESSOR_BY_NAME); assertThat(nonPublicAttributeWithPublicGetterMethod.readReflection(testBean, mockContext)) .isInstanceOf(String.class).isEqualTo(PRIVATE_ACCESSOR_BY_GETTER); } catch (NameNotFoundException | QueryInvocationTargetException exception) { throw new RuntimeException(exception); } }); verify(methodInvocationAuthorizer, times(20)).authorize(any(), any()); }
@Test public void readReflectionForImplicitMethodInvocationShouldNotUseCachedAuthorizerResultForCqs() { when(queryExecutionContext.isCqQueryContext()).thenReturn(true); doReturn(true).when(methodInvocationAuthorizer).authorize(any(), any()); AttributeDescriptor nonPublicAttributeWithPublicAccessor = new AttributeDescriptor(typeRegistry, PRIVATE_ACCESSOR_BY_NAME); AttributeDescriptor nonPublicAttributeWithPublicGetterMethod = new AttributeDescriptor(typeRegistry, PRIVATE_ACCESSOR_BY_GETTER); IntStream.range(0, 10).forEach(element -> { try { assertThat( nonPublicAttributeWithPublicAccessor.readReflection(testBean, queryExecutionContext)) .isInstanceOf(String.class).isEqualTo(PRIVATE_ACCESSOR_BY_NAME); assertThat(nonPublicAttributeWithPublicGetterMethod.readReflection(testBean, queryExecutionContext)).isInstanceOf(String.class) .isEqualTo(PRIVATE_ACCESSOR_BY_GETTER); } catch (NameNotFoundException | QueryInvocationTargetException exception) { throw new RuntimeException(exception); } }); verify(methodInvocationAuthorizer, times(20)).authorize(any(), any()); }
@Test @Parameters({PRIVATE_ACCESSOR_BY_NAME, PRIVATE_ACCESSOR_BY_GETTER}) public void readReflectionForImplicitMethodInvocationShouldThrowExceptionWhenMethodIsNotAuthorized( String attributeName) { doReturn(false).when(methodInvocationAuthorizer).authorize(any(), any()); AttributeDescriptor attributeDescriptor = new AttributeDescriptor(typeRegistry, attributeName); assertThatThrownBy(() -> attributeDescriptor.readReflection(testBean, queryExecutionContext)) .isInstanceOf(NotAuthorizedException.class) .hasMessageStartingWith(RestrictedMethodAuthorizer.UNAUTHORIZED_STRING); }
@Test @Parameters({ "nonPublicAttributeWithPublicAccessor, nonPublicAttributeWithPublicAccessor", "nonPublicAttributeWithPublicGetterMethod, getNonPublicAttributeWithPublicGetterMethod"}) public void readReflectionForImplicitMethodInvocationShouldThrowExceptionWhenMethodIsNotAuthorizedAndCacheResult( String attributeName, String methodName) throws NoSuchMethodException { doReturn(false).when(methodInvocationAuthorizer).authorize(any(), any()); AttributeDescriptor attributeDescriptor = new AttributeDescriptor(typeRegistry, attributeName); assertThatThrownBy(() -> attributeDescriptor.readReflection(testBean, queryExecutionContext)) .isInstanceOf(NotAuthorizedException.class) .hasMessageStartingWith(RestrictedMethodAuthorizer.UNAUTHORIZED_STRING); Method method = TestBean.class.getMethod(methodName); assertThat(queryExecutionContext.cacheGet(method)).isEqualTo(false); }
@Test @Parameters({ "nonPublicAttributeWithPublicAccessor, nonPublicAttributeWithPublicAccessor", "nonPublicAttributeWithPublicGetterMethod, getNonPublicAttributeWithPublicGetterMethod"}) public void readReflectionForImplicitMethodInvocationShouldThrowExceptionWhenMethodIsNotAuthorizedAndDoNotCacheResultForCqs( String attributeName, String methodName) throws NoSuchMethodException { when(queryExecutionContext.isCqQueryContext()).thenReturn(true); doReturn(false).when(methodInvocationAuthorizer).authorize(any(), any()); AttributeDescriptor attributeDescriptor = new AttributeDescriptor(typeRegistry, attributeName); assertThatThrownBy(() -> attributeDescriptor.readReflection(testBean, queryExecutionContext)) .isInstanceOf(NotAuthorizedException.class) .hasMessageStartingWith(RestrictedMethodAuthorizer.UNAUTHORIZED_STRING); Method method = TestBean.class.getMethod(methodName); assertThat(queryExecutionContext.cacheGet(method)).isNull(); }
@Test public void readReflectionForImplicitMethodInvocationShouldUseCachedAuthorizerResultWhenMethodIsForbiddenAndQueryContextIsTheSame() { doReturn(false).when(methodInvocationAuthorizer).authorize(any(), any()); AttributeDescriptor nonPublicAttributeWithPublicAccessor = new AttributeDescriptor(typeRegistry, PRIVATE_ACCESSOR_BY_NAME); AttributeDescriptor nonPublicAttributeWithPublicGetterMethod = new AttributeDescriptor(typeRegistry, PRIVATE_ACCESSOR_BY_GETTER); IntStream.range(0, 10).forEach(element -> { assertThatThrownBy(() -> nonPublicAttributeWithPublicAccessor.readReflection(testBean, queryExecutionContext)).isInstanceOf(NotAuthorizedException.class) .hasMessageStartingWith(RestrictedMethodAuthorizer.UNAUTHORIZED_STRING); assertThatThrownBy(() -> nonPublicAttributeWithPublicGetterMethod.readReflection(testBean, queryExecutionContext)).isInstanceOf(NotAuthorizedException.class) .hasMessageStartingWith(RestrictedMethodAuthorizer.UNAUTHORIZED_STRING); }); verify(methodInvocationAuthorizer, times(2)).authorize(any(), any()); }
@Test public void readReflectionForImplicitMethodInvocationShouldNotUseCachedAuthorizerResultWhenMethodIsForbiddenAndQueryContextIsNotTheSame() { doReturn(false).when(methodInvocationAuthorizer).authorize(any(), any()); AttributeDescriptor nonPublicAttributeWithPublicAccessor = new AttributeDescriptor(typeRegistry, PRIVATE_ACCESSOR_BY_NAME); AttributeDescriptor nonPublicAttributeWithPublicGetterMethod = new AttributeDescriptor(typeRegistry, PRIVATE_ACCESSOR_BY_GETTER); IntStream.range(0, 10).forEach(element -> { QueryExecutionContext mockContext = mock(QueryExecutionContext.class); when(mockContext.getMethodInvocationAuthorizer()).thenReturn(methodInvocationAuthorizer); assertThatThrownBy( () -> nonPublicAttributeWithPublicAccessor.readReflection(testBean, mockContext)) .isInstanceOf(NotAuthorizedException.class) .hasMessageStartingWith(RestrictedMethodAuthorizer.UNAUTHORIZED_STRING); assertThatThrownBy( () -> nonPublicAttributeWithPublicGetterMethod.readReflection(testBean, mockContext)) .isInstanceOf(NotAuthorizedException.class) .hasMessageStartingWith(RestrictedMethodAuthorizer.UNAUTHORIZED_STRING); }); verify(methodInvocationAuthorizer, times(20)).authorize(any(), any()); }
@Test public void readReflectionForImplicitMethodInvocationShouldNotUseCachedAuthorizerResultWhenMethodIsForbiddenForCqs() { when(queryExecutionContext.isCqQueryContext()).thenReturn(true); doReturn(false).when(methodInvocationAuthorizer).authorize(any(), any()); AttributeDescriptor nonPublicAttributeWithPublicAccessor = new AttributeDescriptor(typeRegistry, PRIVATE_ACCESSOR_BY_NAME); AttributeDescriptor nonPublicAttributeWithPublicGetterMethod = new AttributeDescriptor(typeRegistry, PRIVATE_ACCESSOR_BY_GETTER); IntStream.range(0, 10).forEach(element -> { assertThatThrownBy(() -> nonPublicAttributeWithPublicAccessor.readReflection(testBean, queryExecutionContext)).isInstanceOf(NotAuthorizedException.class) .hasMessageStartingWith(RestrictedMethodAuthorizer.UNAUTHORIZED_STRING); assertThatThrownBy(() -> nonPublicAttributeWithPublicGetterMethod.readReflection(testBean, queryExecutionContext)).isInstanceOf(NotAuthorizedException.class) .hasMessageStartingWith(RestrictedMethodAuthorizer.UNAUTHORIZED_STRING); }); verify(methodInvocationAuthorizer, times(20)).authorize(any(), any()); }