/* * * Copyright 2016 Netflix, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.netflix.genie.web.security.oauth2.pingfederate; import com.google.common.collect.Sets; import com.netflix.genie.test.categories.UnitTest; import com.netflix.spectator.api.Registry; import com.netflix.spectator.api.Timer; import org.hamcrest.Matchers; import org.jose4j.jwt.JwtClaims; import org.jose4j.jwt.MalformedClaimException; import org.jose4j.jwt.consumer.InvalidJwtException; import org.jose4j.jwt.consumer.JwtConsumer; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import org.mockito.Mockito; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.oauth2.common.exceptions.InvalidTokenException; import org.springframework.security.oauth2.provider.OAuth2Authentication; import java.util.Collection; import java.util.Set; import java.util.UUID; import java.util.concurrent.TimeUnit; /** * Unit tests for the PingFederateJWTTokenServices class. * * @author tgianos * @since 3.0.0 */ @Category(UnitTest.class) public class PingFederateJWTTokenServicesUnitTests { private Timer loadAuthenticationTimer; private JwtConsumer jwtConsumer; private PingFederateJWTTokenServices tokenServices; /** * Setup for the tests. */ @Before public void setup() { this.loadAuthenticationTimer = Mockito.mock(Timer.class); final Registry registry = Mockito.mock(Registry.class); Mockito.when(registry.timer(Mockito.anyString())).thenReturn(this.loadAuthenticationTimer); this.jwtConsumer = Mockito.mock(JwtConsumer.class); this.tokenServices = new PingFederateJWTTokenServices(this.jwtConsumer, registry); } /** * Make sure we can successfully load an authentication. * * @throws AuthenticationException On error * @throws InvalidTokenException When the token is invalid * @throws InvalidJwtException On invalid JWT token * @throws MalformedClaimException A bad claim */ @Test public void canLoadAuthentication() throws AuthenticationException, InvalidTokenException, InvalidJwtException, MalformedClaimException { final JwtClaims claims = Mockito.mock(JwtClaims.class); final String clientId = UUID.randomUUID().toString(); final String scope1 = "genie_admin"; final String scope2 = UUID.randomUUID().toString(); final Set<String> scopes = Sets.newHashSet(scope1, scope2); Mockito.when(claims.getClaimValue("client_id", String.class)).thenReturn(clientId); Mockito.when(claims.getClaimValue("scope", Collection.class)).thenReturn(scopes); Mockito.when(this.jwtConsumer.processToClaims(Mockito.anyString())).thenReturn(claims); final OAuth2Authentication authentication = this.tokenServices.loadAuthentication(UUID.randomUUID().toString()); Assert.assertNull(authentication.getUserAuthentication()); Assert.assertThat(authentication.getPrincipal(), Matchers.is(clientId)); final Collection<GrantedAuthority> authorities = authentication.getAuthorities(); Assert.assertThat(authorities.size(), Matchers.is(3)); Assert.assertTrue( authorities.containsAll( Sets.newHashSet( new SimpleGrantedAuthority("ROLE_ADMIN"), new SimpleGrantedAuthority("ROLE_" + scope2.toUpperCase()), new SimpleGrantedAuthority("ROLE_USER") ) ) ); Mockito .verify(this.loadAuthenticationTimer, Mockito.times(1)) .record(Mockito.anyLong(), Mockito.eq(TimeUnit.NANOSECONDS)); } /** * Make sure we can't load authentication if there are no authorities. * * @throws AuthenticationException On error * @throws InvalidTokenException When the token is invalid * @throws InvalidJwtException On invalid JWT token * @throws MalformedClaimException A bad claim */ @Test(expected = InvalidTokenException.class) public void cantLoadAuthentication() throws AuthenticationException, InvalidTokenException, InvalidJwtException, MalformedClaimException { final JwtClaims claims = Mockito.mock(JwtClaims.class); final String clientId = UUID.randomUUID().toString(); final Set<String> scopes = Sets.newHashSet(); Mockito.when(claims.getClaimValue("client_id", String.class)).thenReturn(clientId); Mockito.when(claims.getClaimValue("scope", Collection.class)).thenReturn(scopes); Mockito.when(this.jwtConsumer.processToClaims(Mockito.anyString())).thenReturn(claims); this.tokenServices.loadAuthentication(UUID.randomUUID().toString()); Mockito .verify(this.loadAuthenticationTimer, Mockito.times(1)) .record(Mockito.anyLong(), Mockito.eq(TimeUnit.NANOSECONDS)); } /** * Make sure we can't load authentication if an exception is thrown. * * @throws AuthenticationException On error * @throws InvalidTokenException When the token is invalid * @throws InvalidJwtException On invalid JWT token * @throws MalformedClaimException A bad claim */ @Test public void cantProcessClaims() throws AuthenticationException, InvalidTokenException, InvalidJwtException, MalformedClaimException { final JwtClaims claims = Mockito.mock(JwtClaims.class); Mockito.when(claims.getClaimValue("client_id", String.class)) .thenThrow(new MalformedClaimException("bad claim")); Mockito.when(this.jwtConsumer.processToClaims(Mockito.anyString())) .thenThrow(new InvalidJwtException("bad jwt")) .thenReturn(claims); try { this.tokenServices.loadAuthentication(UUID.randomUUID().toString()); Assert.fail(); } catch (final InvalidTokenException e) { Mockito.verify(this.jwtConsumer, Mockito.times(1)).processToClaims(Mockito.anyString()); } try { this.tokenServices.loadAuthentication(UUID.randomUUID().toString()); Assert.fail(); } catch (final InvalidTokenException e) { Mockito.verify(this.jwtConsumer, Mockito.times(2)).processToClaims(Mockito.anyString()); } Mockito .verify(this.loadAuthenticationTimer, Mockito.times(2)) .record(Mockito.anyLong(), Mockito.eq(TimeUnit.NANOSECONDS)); } /** * This method shouldn't be supported by this implementation. */ @Test(expected = UnsupportedOperationException.class) public void readAccessTokenNotSupported() { this.tokenServices.readAccessToken(UUID.randomUUID().toString()); } }