ClientAuthenticator { public Optional<Client> authenticate(Principal principal, boolean createMissingClient) { Optional<String> possibleClientName = getClientName(principal); Optional<URI> possibleClientSpiffeId = getSpiffeId(principal); Optional<Client> possibleClientFromName = possibleClientName.flatMap((name) -> { if (clientAuthConfig.typeConfig().useCommonName()) { return clientDAOReadOnly.getClientByName(name); } else { return Optional.empty(); } }); Optional<Client> possibleClientFromSpiffeId = possibleClientSpiffeId.flatMap((spiffeId) -> { if (clientAuthConfig.typeConfig().useSpiffeId()) { return clientDAOReadOnly.getClientBySpiffeId(spiffeId); } else { return Optional.empty(); } }); if (possibleClientFromName.isPresent() && possibleClientFromSpiffeId.isPresent()) { if (!possibleClientFromName.get().equals(possibleClientFromSpiffeId.get())) { throw new NotAuthorizedException(format( "Input principal's CN and SPIFFE ID correspond to different clients! (cn = %s, spiffe = %s)", possibleClientFromName.get().getName(), possibleClientFromSpiffeId.get().getName())); } } else if (possibleClientFromName.isEmpty() && possibleClientFromSpiffeId.isEmpty()) { return handleMissingClient(createMissingClient, possibleClientName.orElse(""), possibleClientSpiffeId); } Client client = possibleClientFromName .or(() -> possibleClientFromSpiffeId) .orElseThrow(() -> new IllegalStateException( "Unable to identify client, and fallback code in server did not handle this case")); clientDAOReadWrite.sawClient(client, principal); if (client.isEnabled()) { return Optional.of(client); } else { logger.warn("Client {} authenticated but disabled via DB", client); return Optional.empty(); } } ClientAuthenticator(
      ClientDAO clientDAOReadWrite,
      ClientDAO clientDAOReadOnly,
      ClientAuthConfig clientAuthConfig); Optional<Client> authenticate(Principal principal, boolean createMissingClient);  }
@Test public void returnsClientWhenClientPresent_simplePrincipal() { assertThat(authenticator.authenticate(simplePrincipal, true)).isEqualTo(Optional.of(client)); }
@Test public void retrievesClientIfPresent_certPrincipal() { assertThat(authenticator.authenticate(certPrincipal, false)).isEqualTo(Optional.of(client)); }
@Test public void rejectsDisabledClients() { Client disabledClient = new Client(1, "disabled", null, null, null, null, null, null, null, null, false, false ); when(clientDAO.getClientByName("disabled")).thenReturn(Optional.of(disabledClient)); assertThat(authenticator.authenticate(SimplePrincipal.of("CN=disabled"), true)).isEmpty(); }
@Test public void createsDbRecordForNewClient_whenConfigured() { ApiDate now = ApiDate.now(); Client newClient = new Client(2345L, "new-client", "desc", null, now, "automatic", now, "automatic", null, null, true, false ); when(clientDAO.getClientByName("new-client")).thenReturn(Optional.empty()); when(clientDAO.createClient(eq("new-client"), eq("automatic"), any(), any())).thenReturn(2345L); when(clientDAO.getClientById(2345L)).thenReturn(Optional.of(newClient)); assertThat(authenticator.authenticate(SimplePrincipal.of("CN=new-client"), true)).isEqualTo( Optional.of(newClient)); }
@Test public void doesNotCreateDbRecordForNewClient_whenNotConfigured() { ApiDate now = ApiDate.now(); Client newClient = new Client(2345L, "new-client", "desc", null, now, "automatic", now, "automatic", null, null, true, false ); when(clientDAO.getClientByName("new-client")).thenReturn(Optional.empty()); when(clientDAO.createClient(eq("new-client"), eq("automatic"), any(), any())).thenReturn(2345L); when(clientDAO.getClientById(2345L)).thenReturn(Optional.of(newClient)); assertThat(authenticator.authenticate(SimplePrincipal.of("CN=new-client"), false)).isEmpty(); verify(clientDAO, never()).createClient(anyString(), anyString(), anyString(), any()); }
@Test public void updatesClientLastSeen() { assertThat(authenticator.authenticate(simplePrincipal, true)).isPresent(); verify(clientDAO, times(1)).sawClient(any(), eq(simplePrincipal)); }
@Test(expected = NotAuthorizedException.class) public void rejectsCertMatchingMultipleClients() { ApiDate now = ApiDate.now(); Client otherClient = new Client(2345L, "other-client", "desc", null, now, "automatic", now, "automatic", null, null, true, false ); when(clientDAO.getClientByName(clientName)).thenReturn(Optional.of(client)); when(clientDAO.getClientBySpiffeId(clientSpiffe)).thenReturn(Optional.of(otherClient)); authenticator.authenticate(certPrincipal, true); }
@Test public void respectsClientAuthConfig() { ApiDate now = ApiDate.now(); Client otherClient = new Client(2345L, "other-client", "desc", null, now, "automatic", now, "automatic", null, null, true, false ); when(clientDAO.getClientByName(clientName)).thenReturn(Optional.of(client)); when(clientDAO.getClientBySpiffeId(clientSpiffe)).thenReturn( Optional.of(otherClient)); when(clientAuthTypeConfig.useCommonName()).thenReturn(true); when(clientAuthTypeConfig.useSpiffeId()).thenReturn(false); assertThat(authenticator.authenticate(certPrincipal, false)).isEqualTo(Optional.of(client)); when(clientAuthTypeConfig.useCommonName()).thenReturn(false); when(clientAuthTypeConfig.useSpiffeId()).thenReturn(true); assertThat(authenticator.authenticate(certPrincipal, false)).isEqualTo( Optional.of(otherClient)); }
@Test public void ignoresMultipleSpiffeIds() throws Exception { CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate multipleSpiffeClientCert = (X509Certificate) cf.generateCertificate( new ByteArrayInputStream(multipleSpiffePem.getBytes(UTF_8))); Principal multipleSpiffePrincipal = new CertificatePrincipal(multipleSpiffeClientCert.getSubjectDN().toString(), new X509Certificate[] {multipleSpiffeClientCert}); when(clientAuthTypeConfig.useCommonName()).thenReturn(false); when(clientAuthTypeConfig.useSpiffeId()).thenReturn(true); assertThat(authenticator.authenticate(multipleSpiffePrincipal, false)).isEmpty(); verifyNoInteractions(clientDAO); }
@Test public void ignoresMultipleUris() throws Exception { CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate multipleUriClientCert = (X509Certificate) cf.generateCertificate( new ByteArrayInputStream(multipleUriPem.getBytes(UTF_8))); Principal multipleUriPrincipal = new CertificatePrincipal(multipleUriClientCert.getSubjectDN().toString(), new X509Certificate[] {multipleUriClientCert}); when(clientAuthTypeConfig.useCommonName()).thenReturn(false); when(clientAuthTypeConfig.useSpiffeId()).thenReturn(true); assertThat(authenticator.authenticate(multipleUriPrincipal, false)).isEmpty(); verifyNoInteractions(clientDAO); }