-
Notifications
You must be signed in to change notification settings - Fork 392
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[#1185] feat(server-common): Server supports Kerberos authentication #1614
Changes from 24 commits
7da6d1b
2875d79
96d054d
de6629c
e2ba106
d528823
e6e93f2
f8c8918
f8c4bc8
d255848
a53cf2e
701e558
f25fa23
88f3c68
d82cc41
83a98de
af1205d
3bb5d4d
c0b133f
f3ba81e
0423104
82c43cc
e9a859b
0c7699f
4fa5522
34aa6f1
0339177
3738aa5
9f59254
14b7fa7
d4a252d
7c39424
62c782f
247ce36
ada86ac
e7aa618
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,5 +8,6 @@ | |
public enum AuthenticatorType { | ||
NONE, | ||
SIMPLE, | ||
OAUTH | ||
OAUTH, | ||
KERBEROS | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
/** | ||
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license | ||
* agreements. See the NOTICE file distributed with this work for additional information regarding | ||
* copyright ownership. The ASF licenses this file to you 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 | ||
* | ||
* <p>http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* <p>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.datastrato.gravitino.auth; | ||
|
||
import java.security.Principal; | ||
import java.security.PrivilegedActionException; | ||
import java.security.PrivilegedExceptionAction; | ||
import java.util.HashMap; | ||
import java.util.HashSet; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.concurrent.Callable; | ||
import javax.security.auth.Subject; | ||
import javax.security.auth.kerberos.KerberosPrincipal; | ||
import javax.security.auth.login.AppConfigurationEntry; | ||
import javax.security.auth.login.Configuration; | ||
import javax.security.auth.login.LoginContext; | ||
import org.ietf.jgss.GSSException; | ||
import org.ietf.jgss.Oid; | ||
|
||
// Referred from Apache Hadoop KerberosTestUtils.java | ||
// hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/\ | ||
// authentication/KerberosTestUtils.java | ||
public class KerberosUtils { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still the same thing here, please point out which part did you modify for what purpose. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. |
||
|
||
private KerberosUtils() {} | ||
|
||
public static final Oid GSS_SPNEGO_MECH_OID = getNumericOidInstance("1.3.6.1.5.5.2"); | ||
public static final Oid GSS_KRB5_MECH_OID = getNumericOidInstance("1.2.840.113554.1.2.2"); | ||
public static final Oid NT_GSS_KRB5_PRINCIPAL_OID = | ||
getNumericOidInstance("1.2.840.113554.1.2.2.1"); | ||
|
||
// numeric oids will never generate a GSSException for a malformed oid. | ||
// use to initialize statics. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Capitalize the first letter. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. |
||
private static Oid getNumericOidInstance(String oidName) { | ||
try { | ||
return new Oid(oidName); | ||
} catch (GSSException ex) { | ||
throw new IllegalArgumentException(ex); | ||
} | ||
} | ||
|
||
public static <T> T doAs(String principal, String keyTabFile, final Callable<T> callable) | ||
throws Exception { | ||
LoginContext loginContext = null; | ||
try { | ||
Set<Principal> principals = new HashSet<>(); | ||
principals.add(new KerberosPrincipal(principal)); | ||
Subject subject = new Subject(false, principals, new HashSet<>(), new HashSet<>()); | ||
loginContext = | ||
new LoginContext("", subject, null, new KerberosConfiguration(principal, keyTabFile)); | ||
loginContext.login(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we have to login everytime, is it a typical implementation? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Split this into two methods. |
||
subject = loginContext.getSubject(); | ||
return Subject.doAs( | ||
subject, | ||
new PrivilegedExceptionAction<T>() { | ||
@Override | ||
public T run() throws Exception { | ||
return callable.call(); | ||
} | ||
}); | ||
} catch (PrivilegedActionException ex) { | ||
throw ex.getException(); | ||
} finally { | ||
if (loginContext != null) { | ||
loginContext.logout(); | ||
} | ||
} | ||
} | ||
|
||
private static class KerberosConfiguration extends Configuration { | ||
private final String principal; | ||
private final String keyTabFile; | ||
|
||
public KerberosConfiguration(String principal, String keyTabFile) { | ||
this.principal = principal; | ||
this.keyTabFile = keyTabFile; | ||
} | ||
|
||
@Override | ||
public AppConfigurationEntry[] getAppConfigurationEntry(String name) { | ||
Map<String, String> options = new HashMap<String, String>(); | ||
|
||
options.put("keyTab", keyTabFile); | ||
options.put("principal", principal); | ||
options.put("useKeyTab", "true"); | ||
options.put("storeKey", "true"); | ||
options.put("doNotPrompt", "true"); | ||
options.put("useTicketCache", "true"); | ||
options.put("renewTGT", "true"); | ||
options.put("refreshKrb5Config", "true"); | ||
options.put("isInitiator", "true"); | ||
String ticketCache = System.getenv("KRB5CCNAME"); | ||
if (ticketCache != null) { | ||
options.put("ticketCache", ticketCache); | ||
} | ||
options.put("debug", "true"); | ||
|
||
return new AppConfigurationEntry[] { | ||
new AppConfigurationEntry( | ||
getKrb5LoginModuleName(), | ||
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, | ||
options), | ||
}; | ||
} | ||
} | ||
|
||
/* Return the Kerberos login module name */ | ||
public static String getKrb5LoginModuleName() { | ||
return "com.sun.security.auth.module.Krb5LoginModule"; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -255,3 +255,7 @@ components: | |
type: http | ||
scheme: basic | ||
|
||
KerberosAuth: | ||
type: http | ||
scheme: negotiate | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,15 +53,17 @@ GravitinoClient client = GravitinoClient.builder(uri) | |
|
||
### Server configuration | ||
|
||
| Configuration item | Description | Default value | Required | Since version | | ||
|---------------------------------------------------|-----------------------------------------------------------------------------|-------------------|-----------------------------------------|---------------| | ||
| `gravitino.authenticator` | The authenticator which Gravitino uses, setting as `simple` or `oauth`. | `simple` | No | 0.3.0 | | ||
| `gravitino.authenticator.oauth.serviceAudience` | The audience name when Gravitino uses OAuth as the authenticator. | `GravitinoServer` | No | 0.3.0 | | ||
| `gravitino.authenticator.oauth.allowSkewSecs` | The JWT allows skew seconds when Gravitino uses OAuth as the authenticator. | `0` | No | 0.3.0 | | ||
| `gravitino.authenticator.oauth.defaultSignKey` | The signing key of JWT when Gravitino uses OAuth as the authenticator. | (none) | Yes if use `oauth` as the authenticator | 0.3.0 | | ||
| `gravitino.authenticator.oauth.signAlgorithmType` | The signature algorithm when Gravitino uses OAuth as the authenticator. | `RS256` | No | 0.3.0 | | ||
| `gravitino.authenticator.oauth.serverUri` | The URI of the default OAuth server. | (none) | Yes if use `oauth` as the authenticator | 0.3.0 | | ||
| `gravitino.authenticator.oauth.tokenPath` | The path for token of the default OAuth server. | (none) | Yes if use `oauth` as the authenticator | 0.3.0 | | ||
| Configuration item | Description | Default value | Required | Since version | | ||
|---------------------------------------------------|-----------------------------------------------------------------------------|-------------------|--------------------------------------------|---------------| | ||
| `gravitino.authenticator` | The authenticator which Gravitino uses, setting as `simple` or `oauth`. | `simple` | No | 0.3.0 | | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you need to update this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. |
||
| `gravitino.authenticator.oauth.serviceAudience` | The audience name when Gravitino uses OAuth as the authenticator. | `GravitinoServer` | No | 0.3.0 | | ||
| `gravitino.authenticator.oauth.allowSkewSecs` | The JWT allows skew seconds when Gravitino uses OAuth as the authenticator. | `0` | No | 0.3.0 | | ||
| `gravitino.authenticator.oauth.defaultSignKey` | The signing key of JWT when Gravitino uses OAuth as the authenticator. | (none) | Yes if use `oauth` as the authenticator | 0.3.0 | | ||
| `gravitino.authenticator.oauth.signAlgorithmType` | The signature algorithm when Gravitino uses OAuth as the authenticator. | `RS256` | No | 0.3.0 | | ||
| `gravitino.authenticator.oauth.serverUri` | The URI of the default OAuth server. | (none) | Yes if use `oauth` as the authenticator | 0.3.0 | | ||
| `gravitino.authenticator.oauth.tokenPath` | The path for token of the default OAuth server. | (none) | Yes if use `oauth` as the authenticator | 0.3.0 | | ||
| `gravitino.authenticator.kerberos.principal` | Indicates the Kerberos principal to be used for HTTP endpoint. | (none) | Yes if use `kerberos` as the authenticator | 0.4.0 | | ||
| `gravitino.authenticator.kerberos.keytab` | Location of the keytab file with the credentials for the principal. | (none) | Yes if use `kerberos` as the authenticator | 0.4.0 | | ||
|
||
The signature algorithms that Gravitino supports follows: | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -59,6 +59,12 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha | |
chain.doFilter(request, response); | ||
} catch (UnauthorizedException ue) { | ||
HttpServletResponse resp = (HttpServletResponse) response; | ||
if (!ue.getChallenges().isEmpty()) { | ||
// Refer to https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/WWW-Authenticate | ||
for (String challenge : ue.getChallenges()) { | ||
resp.setHeader(AuthConstants.HTTP_CHALLENGE_HEADER, challenge); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add more comment here about the reason of this change. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. |
||
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, ue.getMessage()); | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you should also update the start script under "bin".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.