KerberosAuthenticator subclass that fallback to
+ * {@link TimelineAuthenticationConsts}.
+ */
+@Private
+@Unstable
+public class TimelineAuthenticator extends KerberosAuthenticator {
+
+ private static ObjectMapper mapper;
+
+ static {
+ mapper = new ObjectMapper();
+ YarnJacksonJaxbJsonProvider.configObjectMapper(mapper);
+ }
+
+ /**
+ * Returns the fallback authenticator if the server does not use Kerberos
+ * SPNEGO HTTP authentication.
+ *
+ * @return a {@link TimelineAuthenticationConsts} instance.
+ */
+ @Override
+ protected Authenticator getFallBackAuthenticator() {
+ return new TimelineAuthenticator();
+ }
+
+ public static void injectDelegationToken(MapURL.
+ *
+ * @param path
+ * the file path.
+ * @param params
+ * the query string parameters.
+ *
+ * @return a URL
+ *
+ * @throws IOException
+ * thrown if an IO error occurs.
+ */
+ public static URL appendParams(URL url, MapHttpURLConnection. If the current
+ * status code is not 200, it will throw an exception with a detail message
+ * using Server side error messages if available. Otherwise,
+ * {@link TimelineDelegationTokenResponse} will be parsed and returned.
+ *
+ * @param conn
+ * the HttpURLConnection.
+ * @return
+ * @throws IOException
+ * thrown if the current status code is not 200 or the JSON response
+ * cannot be parsed correctly
+ */
+ private static TimelineDelegationTokenResponse validateAndParseResponse(
+ HttpURLConnection conn) throws IOException {
+ int status = conn.getResponseCode();
+ JsonNode json = mapper.readTree(conn.getInputStream());
+ if (status == HttpURLConnection.HTTP_OK) {
+ return mapper.readValue(json, TimelineDelegationTokenResponse.class);
+ } else {
+ // If the status code is not 200, some thing wrong should happen at the
+ // server side, the JSON content is going to contain exception details.
+ // We can use the JSON content to reconstruct the exception object.
+ try {
+ String message =
+ json.get(TimelineAuthenticationConsts.ERROR_MESSAGE_JSON)
+ .getTextValue();
+ String exception =
+ json.get(TimelineAuthenticationConsts.ERROR_EXCEPTION_JSON)
+ .getTextValue();
+ String className =
+ json.get(TimelineAuthenticationConsts.ERROR_CLASSNAME_JSON)
+ .getTextValue();
+
+ try {
+ ClassLoader cl = TimelineAuthenticator.class.getClassLoader();
+ Class> klass = cl.loadClass(className);
+ Constructor> constr = klass.getConstructor(String.class);
+ throw (IOException) constr.newInstance(message);
+ } catch (IOException ex) {
+ throw ex;
+ } catch (Exception ex) {
+ throw new IOException(MessageFormat.format("{0} - {1}", exception,
+ message));
+ }
+ } catch (IOException ex) {
+ if (ex.getCause() instanceof IOException) {
+ throw (IOException) ex.getCause();
+ }
+ throw new IOException(
+ MessageFormat.format("HTTP status [{0}], {1}",
+ status, conn.getResponseMessage()));
+ }
+ }
+ }
+
+}
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/ClientTimelineSecurityInfo.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/ClientTimelineSecurityInfo.java
new file mode 100644
index 0000000..d2b1358
--- /dev/null
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/ClientTimelineSecurityInfo.java
@@ -0,0 +1,83 @@
+/**
+ * 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
+ *
+ * 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 org.apache.hadoop.yarn.security.client;
+
+import java.lang.annotation.Annotation;
+
+import org.apache.hadoop.classification.InterfaceAudience.Public;
+import org.apache.hadoop.classification.InterfaceStability.Unstable;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.KerberosInfo;
+import org.apache.hadoop.security.SecurityInfo;
+import org.apache.hadoop.security.token.TokenIdentifier;
+import org.apache.hadoop.security.token.TokenInfo;
+import org.apache.hadoop.security.token.TokenSelector;
+import org.apache.hadoop.yarn.api.ApplicationHistoryProtocolPB;
+import org.apache.hadoop.yarn.conf.YarnConfiguration;
+
+
+@Public
+@Unstable
+public class ClientTimelineSecurityInfo extends SecurityInfo {
+ @Override
+ public KerberosInfo getKerberosInfo(Class> protocol, Configuration conf) {
+ if (!protocol
+ .equals(ApplicationHistoryProtocolPB.class)) {
+ return null;
+ }
+ return new KerberosInfo() {
+
+ @Override
+ public Class extends Annotation> annotationType() {
+ return null;
+ }
+
+ @Override
+ public String serverPrincipal() {
+ return YarnConfiguration.TIMELINE_SERVICE_PRINCIPAL;
+ }
+
+ @Override
+ public String clientPrincipal() {
+ return null;
+ }
+ };
+ }
+
+ @Override
+ public TokenInfo getTokenInfo(Class> protocol, Configuration conf) {
+ if (!protocol
+ .equals(ApplicationHistoryProtocolPB.class)) {
+ return null;
+ }
+ return new TokenInfo() {
+
+ @Override
+ public Class extends Annotation> annotationType() {
+ return null;
+ }
+
+ @Override
+ public Class extends TokenSelector extends TokenIdentifier>>
+ value() {
+ return TimelineDelegationTokenSelector.class;
+ }
+ };
+ }
+}
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/TimelineAuthenticationConsts.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/TimelineAuthenticationConsts.java
new file mode 100644
index 0000000..e89e1a6
--- /dev/null
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/TimelineAuthenticationConsts.java
@@ -0,0 +1,44 @@
+/**
+ * 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
+ *
+ * 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 org.apache.hadoop.yarn.security.client;
+
+import org.apache.hadoop.classification.InterfaceAudience.Private;
+import org.apache.hadoop.classification.InterfaceStability.Unstable;
+
+/**
+ * The constants that are going to be used by the timeline Kerberos + delegation
+ * token authentication.
+ */
+
+@Private
+@Unstable
+public class TimelineAuthenticationConsts {
+
+ public static final String ERROR_EXCEPTION_JSON = "exception";
+ public static final String ERROR_CLASSNAME_JSON = "javaClassName";
+ public static final String ERROR_MESSAGE_JSON = "message";
+
+ public static final String OP_PARAM = "op";
+ public static final String DELEGATION_PARAM = "delegation";
+ public static final String TOKEN_PARAM = "token";
+ public static final String RENEWER_PARAM = "renewer";
+ public static final String DELEGATION_TOKEN_URL = "url";
+ public static final String DELEGATION_TOKEN_EXPIRATION_TIME =
+ "expirationTime";
+}
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/TimelineDelegationTokenIdentifier.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/TimelineDelegationTokenIdentifier.java
new file mode 100644
index 0000000..82e0d69
--- /dev/null
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/TimelineDelegationTokenIdentifier.java
@@ -0,0 +1,63 @@
+/**
+ * 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
+ *
+ * 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 org.apache.hadoop.yarn.security.client;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceAudience.Public;
+import org.apache.hadoop.classification.InterfaceStability.Unstable;
+import org.apache.hadoop.io.Text;
+import org.apache.hadoop.security.token.Token;
+import org.apache.hadoop.security.token.delegation.AbstractDelegationTokenIdentifier;
+
+@Public
+@Unstable
+public class TimelineDelegationTokenIdentifier extends AbstractDelegationTokenIdentifier {
+
+ public static final Text KIND_NAME = new Text("TIMELINE_DELEGATION_TOKEN");
+
+ public TimelineDelegationTokenIdentifier() {
+
+ }
+
+ /**
+ * Create a new timeline delegation token identifier
+ *
+ * @param owner the effective username of the token owner
+ * @param renewer the username of the renewer
+ * @param realUser the real username of the token owner
+ */
+ public TimelineDelegationTokenIdentifier(Text owner, Text renewer,
+ Text realUser) {
+ super(owner, renewer, realUser);
+ }
+
+ @Override
+ public Text getKind() {
+ return KIND_NAME;
+ }
+
+ @InterfaceAudience.Private
+ public static class Renewer extends Token.TrivialRenewer {
+ @Override
+ protected Text getKind() {
+ return KIND_NAME;
+ }
+ }
+
+}
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/TimelineDelegationTokenOperation.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/TimelineDelegationTokenOperation.java
new file mode 100644
index 0000000..33ab178
--- /dev/null
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/TimelineDelegationTokenOperation.java
@@ -0,0 +1,55 @@
+/**
+ * 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
+ *
+ * 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 org.apache.hadoop.yarn.security.client;
+
+import org.apache.hadoop.classification.InterfaceAudience.Private;
+import org.apache.hadoop.classification.InterfaceStability.Unstable;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPut;
+
+/**
+ * DelegationToken operations.
+ */
+@Unstable
+@Private
+public enum TimelineDelegationTokenOperation {
+ // TODO: need think about which ops can be done without kerberos
+ // credentials, for safety, we enforces all need kerberos credentials now.
+ GETDELEGATIONTOKEN(HttpGet.METHOD_NAME, true),
+ RENEWDELEGATIONTOKEN(HttpPut.METHOD_NAME, true),
+ CANCELDELEGATIONTOKEN(HttpPut.METHOD_NAME, true);
+
+ private String httpMethod;
+ private boolean requiresKerberosCredentials;
+
+ private TimelineDelegationTokenOperation(String httpMethod,
+ boolean requiresKerberosCredentials) {
+ this.httpMethod = httpMethod;
+ this.requiresKerberosCredentials = requiresKerberosCredentials;
+ }
+
+ public String getHttpMethod() {
+ return httpMethod;
+ }
+
+ public boolean requiresKerberosCredentials() {
+ return requiresKerberosCredentials;
+ }
+
+}
\ No newline at end of file
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/TimelineDelegationTokenSelector.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/TimelineDelegationTokenSelector.java
new file mode 100644
index 0000000..df1e84d
--- /dev/null
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/client/TimelineDelegationTokenSelector.java
@@ -0,0 +1,62 @@
+/**
+ * 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
+ *
+ * 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 org.apache.hadoop.yarn.security.client;
+
+import java.util.Collection;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.classification.InterfaceAudience.Public;
+import org.apache.hadoop.classification.InterfaceStability.Unstable;
+import org.apache.hadoop.io.Text;
+import org.apache.hadoop.security.token.Token;
+import org.apache.hadoop.security.token.TokenIdentifier;
+import org.apache.hadoop.security.token.TokenSelector;
+
+@Public
+@Unstable
+public class TimelineDelegationTokenSelector
+ implements TokenSelector+ * Initializes {@link TimelineAuthenticationFilter} which provides support for + * Kerberos HTTP SPNEGO authentication. + *
+ *+ * It enables Kerberos HTTP SPNEGO plus delegation token authentication for the + * timeline server. + *
+ * Refer to thecore-default.xml file, after the comment 'HTTP
+ * Authentication' for details on the configuration options. All related
+ * configuration properties have 'hadoop.http.authentication.' as prefix.
+ */
+public class TimelineAuthenticationFilterInitializer extends FilterInitializer {
+
+ /**
+ * The configuration prefix of timeline Kerberos + DT authentication
+ */
+ public static final String PREFIX = "yarn.timeline-service.http.authentication.";
+
+ private static final String SIGNATURE_SECRET_FILE =
+ TimelineAuthenticationFilter.SIGNATURE_SECRET + ".file";
+
+ /**
+ * + * Initializes {@link TimelineAuthenticationFilter} + *
+ *+ * Propagates to {@link TimelineAuthenticationFilter} configuration all YARN + * configuration properties prefixed with + * "yarn.timeline-service.authentication." + *
+ * + * @param container + * The filter container + * @param conf + * Configuration for run-time parameters + */ + @Override + public void initFilter(FilterContainer container, Configuration conf) { + MapAuthenticationHandler that authenticates requests
+ * using the incoming delegation token as a 'delegation' query string parameter.
+ *
+ * If not delegation token is present in the request it delegates to the
+ * {@link KerberosAuthenticationHandler}
+ */
+@Private
+@Unstable
+public class TimelineClientAuthenticationService
+ extends KerberosAuthenticationHandler {
+
+ public static final String TYPE = "kerberos-dt";
+ private static final Setdelegationtoken-kerberos
+ */
+ @Override
+ public String getType() {
+ return TYPE;
+ }
+
+ @Override
+ public boolean managementOperation(AuthenticationToken token,
+ HttpServletRequest request, HttpServletResponse response)
+ throws IOException, AuthenticationException {
+ boolean requestContinues = true;
+ String op = request.getParameter(OP_PARAM);
+ op = (op != null) ? op.toUpperCase() : null;
+ if (DELEGATION_TOKEN_OPS.contains(op) &&
+ !request.getMethod().equals("OPTIONS")) {
+ TimelineDelegationTokenOperation dtOp =
+ TimelineDelegationTokenOperation.valueOf(op);
+ if (dtOp.getHttpMethod().equals(request.getMethod())) {
+ if (dtOp.requiresKerberosCredentials() && token == null) {
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
+ MessageFormat.format(
+ "Operation [{0}] requires SPNEGO authentication established",
+ dtOp));
+ requestContinues = false;
+ } else {
+ TimelineDelegationTokenSecretManagerService secretManager =
+ AHSWebApp.getInstance()
+ .getTimelineDelegationTokenSecretManagerService();
+ try {
+ TimelineDelegationTokenResponse res = null;
+ switch (dtOp) {
+ case GETDELEGATIONTOKEN:
+ UserGroupInformation ownerUGI =
+ UserGroupInformation.createRemoteUser(token.getUserName());
+ String renewerParam =
+ request
+ .getParameter(TimelineAuthenticationConsts.RENEWER_PARAM);
+ if (renewerParam == null) {
+ renewerParam = token.getUserName();
+ }
+ Token> dToken =
+ secretManager.createToken(ownerUGI, renewerParam);
+ res = new TimelineDelegationTokenResponse();
+ res.setType(TimelineAuthenticationConsts.DELEGATION_TOKEN_URL);
+ res.setContent(dToken.encodeToUrlString());
+ break;
+ case RENEWDELEGATIONTOKEN:
+ case CANCELDELEGATIONTOKEN:
+ String tokenParam =
+ request
+ .getParameter(TimelineAuthenticationConsts.TOKEN_PARAM);
+ if (tokenParam == null) {
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST,
+ MessageFormat
+ .format(
+ "Operation [{0}] requires the parameter [{1}]",
+ dtOp,
+ TimelineAuthenticationConsts.TOKEN_PARAM));
+ requestContinues = false;
+ } else {
+ if (dtOp == TimelineDelegationTokenOperation.CANCELDELEGATIONTOKEN) {
+ Tokendelegation
+ * query-string parameter and verifying it is a valid token. If there is not
+ * delegation query-string parameter, it delegates the
+ * authentication to the {@link KerberosAuthenticationHandler} unless it is
+ * disabled.
+ *
+ * @param request
+ * the HTTP client request.
+ * @param response
+ * the HTTP client response.
+ *
+ * @return the authentication token for the authenticated request.
+ * @throws IOException
+ * thrown if an IO error occurred.
+ * @throws AuthenticationException
+ * thrown if the authentication failed.
+ */
+ @Override
+ public AuthenticationToken authenticate(HttpServletRequest request,
+ HttpServletResponse response)
+ throws IOException, AuthenticationException {
+ AuthenticationToken token;
+ String delegationParam =
+ request
+ .getParameter(TimelineAuthenticationConsts.DELEGATION_PARAM);
+ if (delegationParam != null) {
+ Token