
com.mongodb.KerberosSubjectProvider Maven / Gradle / Ivy
/*
* Copyright 2008-present MongoDB, 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.mongodb;
import com.mongodb.annotations.ThreadSafe;
import com.mongodb.diagnostics.logging.Logger;
import com.mongodb.diagnostics.logging.Loggers;
import com.mongodb.lang.NonNull;
import javax.security.auth.Subject;
import javax.security.auth.kerberos.KerberosTicket;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import static com.mongodb.assertions.Assertions.notNull;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.MINUTES;
/**
* An implementation of {@link SubjectProvider} suitable for use as the value of the {@link MongoCredential#JAVA_SUBJECT_PROVIDER_KEY}
* mechanism property for Kerberos credentials, created via {@link MongoCredential#createGSSAPICredential(String)}.
*
* An instance of this class will cache a Kerberos {@link Subject} until its TGT is close to expiration, at which point it will replace
* the {@code Subject} with a new one.
*
*
* {@code Subject} instances are created by first constructing a {@link LoginContext} with the specified name, then calling its
* {@link LoginContext#login()} method, and finally acquiring the {@code Subject} via a call to {@link LoginContext#getSubject()}.
*
*
* @see LoginContext
* @see Subject
* @see KerberosTicket
* @since 4.2
*/
@ThreadSafe
public class KerberosSubjectProvider implements SubjectProvider {
private static final Logger LOGGER = Loggers.getLogger("authenticator");
private static final String TGT_PREFIX = "krbtgt/";
private final String loginContextName;
private Subject subject;
/**
* Construct an instance with the default login context name {@code "com.sun.security.jgss.krb5.initiate"}.
*/
public KerberosSubjectProvider() {
this("com.sun.security.jgss.krb5.initiate");
}
/**
* Construct an instance with the specified login context name
*
* @param loginContextName the login context name
*/
public KerberosSubjectProvider(@NonNull final String loginContextName) {
this.loginContextName = notNull("loginContextName", loginContextName);
}
/**
* Gets a {@code Subject} instance associated with a {@link LoginContext} after its been logged in.
*
* @return the non-null {@code Subject} instance
* @throws LoginException any exception resulting from a call to {@link LoginContext#login()}
*/
@NonNull
public synchronized Subject getSubject() throws LoginException {
if (subject == null || needNewSubject(subject)) {
LOGGER.info("Creating new LoginContext and logging in the principal");
LoginContext loginContext = new LoginContext(loginContextName);
loginContext.login();
subject = loginContext.getSubject();
LOGGER.info("Login successful");
}
return subject;
}
private static boolean needNewSubject(@NonNull final Subject subject) {
for (KerberosTicket cur : subject.getPrivateCredentials(KerberosTicket.class)) {
if (cur.getServer().getName().startsWith(TGT_PREFIX)) {
if (System.currentTimeMillis() > cur.getEndTime().getTime() - MILLISECONDS.convert(5, MINUTES)) {
LOGGER.info("The TGT is close to expiring. Time to reacquire.");
return true;
}
break;
}
}
return false;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy