Skip to content

Commit

Permalink
Merge pull request #49 from bedrin/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
bedrin authored Dec 30, 2022
2 parents f5369b0 + a525c20 commit 54eceef
Show file tree
Hide file tree
Showing 23 changed files with 231 additions and 47 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
strategy:
matrix:
# test against latest update of each major Java version, as well as specific updates of LTS versions:
java: [ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17-ea ]
java: [ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ]
os: [ ubuntu-20.04, windows-2019, macos-10.15 ]
name: Test JDK ${{ matrix.java }}, ${{ matrix.os }}
steps:
Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Kerb4J
![Java CI](https://github.com/bedrin/kerb4j/workflows/Java%20CI/badge.svg?branch=develop)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.kerb4j/kerb4j/badge.svg?style=flat)](https://maven-badges.herokuapp.com/maven-central/com.kerb4j/kerb4j)

Industry standard library for working with Kerberos/SPNEGO authentication in Java in 2020+.
Industry standard library for working with Kerberos/SPNEGO authentication in Java in 2023+.

Main features:

Expand All @@ -23,7 +23,7 @@ Kerb4J is available from Maven Central repo:
<dependency>
<groupId>com.kerb4j</groupId>
<artifactId>kerb4j-client</artifactId>
<version>0.1.2</version>
<version>0.1.3</version>
</dependency>
```

Expand All @@ -33,7 +33,7 @@ Kerb4J is available from Maven Central repo:
<dependency>
<groupId>com.kerb4j</groupId>
<artifactId>kerb4j-server-spring-security</artifactId>
<version>0.1.2</version>
<version>0.1.3</version>
</dependency>
```

Expand All @@ -43,7 +43,7 @@ Kerb4J is available from Maven Central repo:
<dependency>
<groupId>com.kerb4j</groupId>
<artifactId>kerb4j-server-tomcat</artifactId>
<version>0.1.2</version>
<version>0.1.3</version>
</dependency>
```

Expand Down Expand Up @@ -108,6 +108,10 @@ Call `spnegoClient.createAcceptContext()` method to create a `SpnegoContext` ins
your client. Pass decoded SPNEGO token (Base64 decoded value of token in 'Authorization: Negotiate' header)
to `spnegoContext.acceptToken` method to validate it.

If you only plan to validate client tokens on your server and do not use credentials delegation or reusing the same `SpnegoClient` for accessing other servers, you can create "offline" `SpengoClient` by passing `acceptOnly = true` parameter to `SpengoClient.loginWithKeyTab` factory method.

Please note that it works with `keytab` secrets only.

Kerb4J comes with an Authenticator for Apache Tomcat (kerb4j-server-tomcat artifact) as well as authentication provider
for Spring Security (See kerb4j-server-spring-security)

Expand Down
2 changes: 1 addition & 1 deletion kerb4j-base64/kerb4j-base64-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<artifactId>kerb4j-base64</artifactId>
<groupId>com.kerb4j</groupId>
<version>0.1.2</version>
<version>0.1.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
2 changes: 1 addition & 1 deletion kerb4j-base64/kerb4j-base64-java7/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<artifactId>kerb4j-base64</artifactId>
<groupId>com.kerb4j</groupId>
<version>0.1.2</version>
<version>0.1.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
4 changes: 2 additions & 2 deletions kerb4j-base64/kerb4j-base64-java8/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<artifactId>kerb4j-base64</artifactId>
<groupId>com.kerb4j</groupId>
<version>0.1.2</version>
<version>0.1.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand All @@ -15,7 +15,7 @@
<dependency>
<groupId>com.kerb4j</groupId>
<artifactId>kerb4j-base64-common</artifactId>
<version>0.1.2</version>
<version>0.1.3</version>
</dependency>
</dependencies>

Expand Down
2 changes: 1 addition & 1 deletion kerb4j-base64/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<artifactId>kerb4j</artifactId>
<groupId>com.kerb4j</groupId>
<version>0.1.2</version>
<version>0.1.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
6 changes: 3 additions & 3 deletions kerb4j-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>com.kerb4j</groupId>
<artifactId>kerb4j</artifactId>
<version>0.1.2</version>
<version>0.1.3</version>
</parent>

<artifactId>kerb4j-client</artifactId>
Expand All @@ -18,12 +18,12 @@
<dependency>
<groupId>com.kerb4j</groupId>
<artifactId>kerb4j-common</artifactId>
<version>0.1.2</version>
<version>0.1.3</version>
</dependency>
<dependency>
<groupId>com.kerb4j</groupId>
<artifactId>kerb4j-common</artifactId>
<version>0.1.2</version>
<version>0.1.3</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
Expand Down
6 changes: 3 additions & 3 deletions kerb4j-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>com.kerb4j</groupId>
<artifactId>kerb4j</artifactId>
<version>0.1.2</version>
<version>0.1.3</version>
</parent>

<artifactId>kerb4j-common</artifactId>
Expand All @@ -18,12 +18,12 @@
<dependency>
<groupId>com.kerb4j</groupId>
<artifactId>kerb4j-base64-java7</artifactId>
<version>0.1.2</version>
<version>0.1.3</version>
</dependency>
<dependency>
<groupId>com.kerb4j</groupId>
<artifactId>kerb4j-base64-java8</artifactId>
<version>0.1.2</version>
<version>0.1.3</version>
</dependency>
<dependency>
<groupId>org.apache.kerby</groupId>
Expand Down
36 changes: 35 additions & 1 deletion kerb4j-common/src/main/java/com/kerb4j/client/SpnegoClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public final class SpnegoClient {
private static final Logger LOGGER = LoggerFactory.getLogger(SpnegoClient.class);
private final static LRUCache<AbstractMap.SimpleEntry<String, String>, SpnegoClient> SPNEGO_CLIENT_CACHE = new LRUCache<>(1024);
private final AtomicReference<SubjectTgtPair> subjectTgtPairReference = new AtomicReference<>();
private final AtomicReference<Subject> eternalSubjectReference = new AtomicReference<>();
private final Callable<Subject> subjectSupplier;
private final Lock authenticateLock = new ReentrantLock();

Expand Down Expand Up @@ -168,10 +169,25 @@ public LoginContext call() throws Exception {
* @param keyTabLocation keyTabLocation
*/
public static SpnegoClient loginWithKeyTab(final String principal, final String keyTabLocation) {
return loginWithKeyTab(principal, keyTabLocation, false);
}

// TODO: add factory methods with implicit principal name

/**
* Creates an instance where authentication is done using keytab file
* Allows customizing underlying isInitiator parameter by using acceptOnly parameter - see description below
*
* @param principal principal
* @param keyTabLocation keyTabLocation
* @param acceptOnly when set to true, SpnegoClient will work offline and ONLY for accepting new tokens. As a result it doesn't require connection to Kerberos server but cannot request new tokens for other services
* @since 0.1.3
*/
public static SpnegoClient loginWithKeyTab(final String principal, final String keyTabLocation, final boolean acceptOnly) {
return new SpnegoClient(new Callable<LoginContext>() {
@Override
public LoginContext call() throws Exception {
return Krb5LoginContext.loginWithKeyTab(principal, keyTabLocation);
return Krb5LoginContext.loginWithKeyTab(principal, keyTabLocation, acceptOnly);
}
});
}
Expand Down Expand Up @@ -205,13 +221,25 @@ public static SpnegoClient loginWithContextSupplier(final Callable<LoginContext>

public Subject getSubject() {

Subject eternalSubject = eternalSubjectReference.get();

if (null != eternalSubject) {
return eternalSubject;
}

SubjectTgtPair subjectTgtPair = subjectTgtPairReference.get();

if (null == subjectTgtPair || subjectTgtPair.isExpired()) {

authenticateLock.lock();
try {

eternalSubject = eternalSubjectReference.get();

if (null != eternalSubject) {
return eternalSubject;
}

subjectTgtPair = subjectTgtPairReference.get();

if (null == subjectTgtPair || subjectTgtPair.isExpired()) {
Expand All @@ -227,6 +255,12 @@ public Subject getSubject() {

subjectTgtPair = subjectTgtPairReference.get();

if (null == subjectTgtPair) {
// isInitiator = false / acceptOnly client
eternalSubjectReference.set(subject);
return subject;
}

}

} catch (RuntimeException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@

import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import static java.util.Collections.emptyMap;

/**
* Implementation of {@link Configuration} which uses Sun's JAAS
* Krb5LoginModule.
Expand Down Expand Up @@ -63,6 +66,17 @@ protected Krb5LoginConfig(Map<String, String> additionalOptions) {
}

public static Krb5LoginConfig createKeyTabClientConfig(String principal, String keyTabLocation) {
return createKeyTabClientConfig(principal, keyTabLocation, Collections.<String,String>emptyMap());
}

/**
* TODO: add since parameter
* @param principal
* @param keyTabLocation
* @param additionalOptions
* @return
*/
public static Krb5LoginConfig createKeyTabClientConfig(String principal, String keyTabLocation, Map<String, String> additionalOptions) {
Map<String, String> options = new HashMap<>();

options.put("principal", principal);
Expand All @@ -72,7 +86,8 @@ public static Krb5LoginConfig createKeyTabClientConfig(String principal, String
options.put("storeKey", "true");

options.put("doNotPrompt", "true");
// TODO: add isInitiator true

options.putAll(additionalOptions);

return new Krb5LoginConfig(options);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import java.util.Collections;

public class Krb5LoginContext extends LoginContext {

Expand All @@ -16,10 +17,16 @@ private Krb5LoginContext(String name, Subject subject, CallbackHandler callbackH
super(name, subject, callbackHandler, config);
}

public static Krb5LoginContext loginWithKeyTab(String principal, String keyTabLocation) {
/**
* @param principal principal
* @param keyTabLocation keyTabLocation
* @param acceptOnly when set to true, SpnegoClient will work offline and ONLY for accepting new tokens. As a result it doesn't require connection to Kerberos server but cannot request new tokens for other services
* @since 0.1.3
*/
public static Krb5LoginContext loginWithKeyTab(String principal, String keyTabLocation, final boolean acceptOnly) {
try {
Krb5LoginContext krb5LoginContext = new Krb5LoginContext(UNUSED_CONFIGURATION_NAME, null, null,
Krb5LoginConfig.createKeyTabClientConfig(principal, keyTabLocation)
Krb5LoginConfig.createKeyTabClientConfig(principal, keyTabLocation, Collections.singletonMap("isInitiator", acceptOnly ? "false" : "true"))
);
krb5LoginContext.login();
return krb5LoginContext;
Expand All @@ -29,6 +36,10 @@ public static Krb5LoginContext loginWithKeyTab(String principal, String keyTabLo
}
}

public static Krb5LoginContext loginWithKeyTab(String principal, String keyTabLocation) {
return loginWithKeyTab(principal, keyTabLocation, false);
}

public static Krb5LoginContext loginWithTicketCache(String principal) {
try {
Krb5LoginContext krb5LoginContext = new Krb5LoginContext(UNUSED_CONFIGURATION_NAME, null, null,
Expand Down
4 changes: 2 additions & 2 deletions kerb4j-server/kerb4j-server-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>com.kerb4j</groupId>
<artifactId>kerb4j-server</artifactId>
<version>0.1.2</version>
<version>0.1.3</version>
</parent>

<artifactId>kerb4j-server-common</artifactId>
Expand All @@ -16,7 +16,7 @@
<dependency>
<groupId>org.apache.kerby</groupId>
<artifactId>kerb-crypto</artifactId>
<version>1.1.0</version>
<version>${kerby.version}</version>
</dependency>
</dependencies>

Expand Down
4 changes: 2 additions & 2 deletions kerb4j-server/kerb4j-server-spring-security-ldap/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
<parent>
<groupId>com.kerb4j</groupId>
<artifactId>kerb4j-server</artifactId>
<version>0.1.2</version>
<version>0.1.3</version>
</parent>

<artifactId>kerb4j-server-spring-security-ldap</artifactId>
<name>kerb4j-server-spring-security-ldap</name>

<properties>
<spring.security.version>5.3.9.RELEASE</spring.security.version>
<spring.security.version>5.7.6</spring.security.version>
</properties>

<dependencies>
Expand Down
6 changes: 3 additions & 3 deletions kerb4j-server/kerb4j-server-spring-security/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
<parent>
<groupId>com.kerb4j</groupId>
<artifactId>kerb4j-server</artifactId>
<version>0.1.2</version>
<version>0.1.3</version>
</parent>

<artifactId>kerb4j-server-spring-security</artifactId>
<name>kerb4j-server-spring-security</name>

<properties>
<io.sniffy.version>3.1.12</io.sniffy.version>
<spring.security.version>5.3.9.RELEASE</spring.security.version>
<io.sniffy.version>3.1.14</io.sniffy.version>
<spring.security.version>5.7.6</spring.security.version>
</properties>

<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ public SpnegoAuthenticationToken authenticate(Authentication authentication) {
SpnegoAuthenticationToken responseAuth = new SpnegoAuthenticationToken(
userDetails.getAuthorities(), ticketValidation.getToken(),
canonicalName, ticketValidation.responseToken(),
ticketValidation.getSubject(), ticketValidation.getKerberosKeys()
ticketValidation.getSubject(), ticketValidation.getKerberosKeys(),
ticketValidation.getEtype()
);
responseAuth.setDetails(authentication.getDetails());

Expand Down
Loading

0 comments on commit 54eceef

Please sign in to comment.