@Override public Subject run() { return SecurityUtil.getSubjectFromTicketCacheOrNull(); } });
private static boolean tgtExpiresBefore(Subject subject, long deadlineMillis) { KerberosTicket tgt = findTgt(subject); if (tgt != null) { return tgt.getEndTime().getTime() < deadlineMillis; } // We didn't find any TGT. This likely means that it expired and got // removed during a connection attempt. So, we need to get a new one. return true; }
private static KerberosTicket findTgt(Subject subject) { Set<KerberosTicket> tickets = subject.getPrivateCredentials(KerberosTicket.class); // tickets is a Collections.synchronizedSet() wrapper, so we need to synchronize // on it to iterate it. synchronized (tickets) { for (KerberosTicket ticket : tickets) { if (SecurityUtil.isTGSPrincipal(ticket.getServer())) { return ticket; } } } return null; }
private static Pair<SubjectType, Subject> setupSubject() { AccessControlContext context = AccessController.getContext(); Subject subject = Subject.getSubject(context); if (subject != null) { if (!subject.getPrincipals(KerberosPrincipal.class).isEmpty()) { LOG.debug("Using caller-provided subject with Kerberos principal {}. " + "Caller is responsible for refreshing credentials.", SecurityUtil.getKerberosPrincipalOrNull(subject)); return new Pair<>(SubjectType.PROVIDED, subject); } LOG.debug("Caller-provided subject {} does not have any Kerberos credentials. " + "Ignoring it.", subject.toString()); } subject = SecurityUtil.getSubjectFromTicketCacheOrNull(); if (subject != null) { return new Pair<>(SubjectType.CREATED, subject); } // If we weren't able to login from a ticket cache when we create the client, // we shouldn't later pick one up. return new Pair<>(SubjectType.NONE, null); }
@Test public void testChannelBinding() throws Exception { KeyStore ks = loadTestKeystore(); Certificate cert = ks.getCertificate("1"); byte[] bindings = SecurityUtil.getEndpointChannelBindings(cert); assertEquals(32, bindings.length); }
Subject localSubject = subject; boolean needed = SecurityUtil.needsRefresh(localSubject); if (!needed) { throw new RuntimeException(e.getCause()); if (newSubject == null || SecurityUtil.getKerberosPrincipalOrNull(newSubject) == null) { LOG.warn("Tried to refresh Kerberos credentials but was unable to re-login from ticket cache"); loggedRefreshFailure = true; KerberosPrincipal oldPrincipal = SecurityUtil.getKerberosPrincipalOrNull(localSubject); KerberosPrincipal principal = SecurityUtil.getKerberosPrincipalOrNull(newSubject); if (!oldPrincipal.equals(principal)) { LOG.error("Attempted to refresh Kerberos credentials from ticket cache but found that " +
/** * @return true if 'subject' contains a Kerberos TGT that is about to expire, or * if it contains no TGT at all. */ public static boolean needsRefresh(Subject subject) { long deadline = System.currentTimeMillis() + REFRESH_BEFORE_EXPIRATION_SECS * 1000; return tgtExpiresBefore(subject, deadline); }
continue; if (SecurityUtil.isTgtExpired(s)) { errorsByMech.put(clientMech.name(), "client Kerberos credentials (TGT) have expired"); continue;
/** * Verify the channel bindings included in 'response'. This is used only * for GSSAPI-authenticated connections over TLS. * @throws SSLPeerUnverifiedException on failure to verify */ private void verifyChannelBindings(NegotiatePB response) throws IOException { byte[] expected = SecurityUtil.getEndpointChannelBindings(peerCert); if (!response.hasChannelBindings()) { throw new SSLPeerUnverifiedException("no channel bindings provided by remote peer"); } byte[] provided = response.getChannelBindings().toByteArray(); // NOTE: the C SASL library's implementation of sasl_encode() actually // includes a length prefix. Java's equivalents do not. So, we have to // chop off the length prefix here before unwrapping. if (provided.length < 4) { throw new SSLPeerUnverifiedException("invalid too-short channel bindings"); } byte[] unwrapped = saslClient.unwrap(provided, 4, provided.length - 4); if (!Bytes.equals(expected, unwrapped)) { throw new SSLPeerUnverifiedException("invalid channel bindings provided by remote peer"); } }
/** * @return true if 'subject' contains a Kerberos TGT that is expired, or if it contains * no TGT at all. */ public static boolean isTgtExpired(Subject subject) { return tgtExpiresBefore(subject, System.currentTimeMillis()); }
startCluster(ImmutableSet.of(Option.SHORT_TOKENS_AND_TICKETS)); Subject subject = SecurityUtil.getSubjectFromTicketCacheOrNull(); Assert.assertNotNull(subject); try (Closeable c = cla.attach()) { Subject newSubject = SecurityUtil.getSubjectFromTicketCacheOrNull(); subject.getPrivateCredentials().clear(); subject.getPrivateCredentials().addAll(newSubject.getPrivateCredentials());
/** * Test that, if an externally-provided subject is used when the client * is created, the client will not attempt to refresh anything, and will * eventually fail with appropriate warnings in the log. */ @Test(timeout=300000) public void testExternallyProvidedSubjectExpires() throws Exception { startCluster(ImmutableSet.of(Option.SHORT_TOKENS_AND_TICKETS)); Subject subject = SecurityUtil.getSubjectFromTicketCacheOrNull(); Assert.assertNotNull(subject); try (Closeable c = cla.attach()) { // Create a client attached to our own subject. KuduClient newClient = createClientFromSubject(subject); // It should not get auto-refreshed. try { assertEventualAuthenticationFailure(newClient, "server requires authentication, but " + "client Kerberos credentials (TGT) have expired"); } finally { newClient.close(); } } Assert.assertThat(cla.getAppendedText(), CoreMatchers.containsString( "Using caller-provided subject with Kerberos principal test-admin@KRBTEST.COM.")); Assert.assertThat(cla.getAppendedText(), CoreMatchers.containsString( "Caller-provided Subject has a Kerberos ticket that is about to expire")); }