All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.zeppelin.realm.kerberos.KerberosRealm Maven / Gradle / Ivy

There is a newer version: 0.11.2
Show newest version
/*
 * 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.zeppelin.realm.kerberos;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.security.Groups;
import org.apache.hadoop.security.authentication.client.AuthenticatedURL;
import org.apache.hadoop.security.authentication.client.AuthenticationException;
import org.apache.hadoop.security.authentication.client.KerberosAuthenticator;
import org.apache.hadoop.security.authentication.server.AuthenticationHandler;
import org.apache.hadoop.security.authentication.server.AuthenticationToken;
import org.apache.commons.codec.binary.Base64;
import org.apache.hadoop.security.authentication.util.*;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.SimpleAccount;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSManager;
import org.ietf.jgss.Oid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.security.auth.Subject;
import javax.security.auth.kerberos.KerberosPrincipal;
import javax.security.auth.kerberos.KeyTab;
import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;

import java.io.File;
import java.io.IOException;
import java.security.Principal;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;

/**
 * The {@link KerberosRealm} implements the Kerberos SPNEGO
 * authentication mechanism for HTTP via Shiro.
 * 

* The Shiro configuration section should be configured as: * [main] * krbRealm = org.apache.zeppelin.realm.kerberos.KerberosRealm * krbRealm.principal=HTTP/[email protected] * krbRealm.keytab=/etc/security/keytabs/spnego.service.keytab * krbRealm.nameRules=DEFAULT * krbRealm.signatureSecretFile=/etc/security/http_secret * krbRealm.tokenValidity=36000 * krbRealm.cookieDomain=domain.com * krbRealm.cookiePath=/ * authc = org.apache.zeppelin.realm.kerberos.KerberosAuthenticationFilter * */ public class KerberosRealm extends AuthorizingRealm { public static final Logger LOG = LoggerFactory.getLogger(KerberosRealm.class); // Configs to set in shiro.ini private String principal = null; private String keytab = null; private String nameRules = "DEFAULT"; private long tokenMaxInactiveInterval = -1; private long tokenValidity = 36000; // 10 hours private String cookieDomain = null; private String cookiePath = "/"; private boolean isCookiePersistent = false; private String signatureSecretFile = null; private String signatureSecretProvider = "file"; /** * Constant for the property that specifies the authentication handler to use. */ private static final String AUTH_TYPE = "type"; /** * Constant for the property that specifies the secret to use for signing the HTTP Cookies. */ private static final String SIGNATURE_SECRET = "signature.secret"; private static final String SIGNATURE_SECRET_FILE = SIGNATURE_SECRET + ".file"; /** * Constant for the configuration property * that indicates the max inactive interval of the generated token. * Currently this is NOT being used * TODO(vr): Enable this when we move to Apache Hadoop 2.8+ */ private static final String AUTH_TOKEN_MAX_INACTIVE_INTERVAL = "token.max-inactive-interval"; /** * Constant for the configuration property that indicates the tokenValidity of the generated * token. */ private static final String AUTH_TOKEN_VALIDITY = "token.tokenValidity"; /** * Constant for the configuration property that indicates the domain to use in the HTTP cookie. */ private static final String COOKIE_DOMAIN = "cookie.domain"; /** * Constant for the configuration property that indicates the path to use in the HTTP cookie. */ private static final String COOKIE_PATH = "cookie.path"; /** * Constant for the configuration property * that indicates the persistence of the HTTP cookie. */ private static final String COOKIE_PERSISTENT = "cookie.persistent"; /** * Constant that identifies the authentication mechanism. */ public static final String TYPE = "kerberos"; /** * Constant for the configuration property that indicates the kerberos * principal. */ public static final String PRINCIPAL = TYPE + ".principal"; /** * Constant for the configuration property that indicates the keytab * file path. */ public static final String KEYTAB = TYPE + ".keytab"; /** * Constant for the configuration property that indicates the Kerberos name * rules for the Kerberos principals. */ public static final String NAME_RULES = TYPE + ".name.rules"; /** * Constant for the configuration property that indicates the name of the * SignerSecretProvider class to use. * Possible values are: "file", "random" * We are NOT supporting "zookeeper", or a custom classname, at the moment. * If not specified, the "file" implementation will be used with * SIGNATURE_SECRET_FILE; and if that's not specified, the "random" * implementation will be used. */ private static final String SIGNER_SECRET_PROVIDER = "signer.secret.provider"; private static Signer signer = null; private SignerSecretProvider secretProvider = null; private boolean destroySecretProvider = true; private GSSManager gssManager = null; private Subject serverSubject = null; private Properties config = null; /** * Hadoop Groups implementation. */ private Groups hadoopGroups; @Override public boolean supports(org.apache.shiro.authc.AuthenticationToken token) { return token instanceof KerberosToken; } /** * Initializes the KerberosRealm by 'kinit'ing using principal and keytab. *

* It creates a Kerberos context using the principal and keytab specified in * the Shiro configuration. *

* This method should be called only once. * * @throws RuntimeException thrown if the handler could not be initialized. */ @Override protected void onInit() { super.onInit(); config = getConfiguration(); try { if (principal == null || principal.trim().length() == 0) { throw new RuntimeException("Principal not defined in configuration"); } if (keytab == null || keytab.trim().length() == 0) { throw new RuntimeException("Keytab not defined in configuration"); } File keytabFile = new File(keytab); if (!keytabFile.exists()) { throw new RuntimeException("Keytab file does not exist: " + keytab); } // use all SPNEGO principals in the keytab if a principal isn't // specifically configured final String[] spnegoPrincipals; if (principal.equals("*")) { spnegoPrincipals = KerberosUtil.getPrincipalNames( keytab, Pattern.compile("HTTP/.*")); if (spnegoPrincipals.length == 0) { throw new RuntimeException("Principals do not exist in the keytab"); } } else { spnegoPrincipals = new String[]{principal}; } KeyTab keytabInstance = KeyTab.getInstance(keytabFile); serverSubject = new Subject(); serverSubject.getPrivateCredentials().add(keytabInstance); for (String spnegoPrincipal : spnegoPrincipals) { Principal krbPrincipal = new KerberosPrincipal(spnegoPrincipal); LOG.info("Using keytab {}, for principal {}", keytab, krbPrincipal); serverSubject.getPrincipals().add(krbPrincipal); } if (nameRules == null || nameRules.trim().length() == 0) { LOG.warn("No auth_to_local rules defined, DEFAULT will be used."); nameRules = "DEFAULT"; } KerberosName.setRules(nameRules); if (null == gssManager) { try { gssManager = Subject.doAs(serverSubject, new PrivilegedExceptionAction() { @Override public GSSManager run() { return GSSManager.getInstance(); } }); LOG.trace("SPNEGO gssManager initialized."); } catch (PrivilegedActionException ex) { throw ex.getException(); } } if (null == signer) { initializeSecretProvider(); } Configuration hadoopConfig = new Configuration(); hadoopGroups = new Groups(hadoopConfig); } catch (Exception ex) { throw new RuntimeException(ex); } } private void initializeSecretProvider() throws ServletException { try { secretProvider = constructSecretProvider(true); destroySecretProvider = true; signer = new Signer(secretProvider); } catch (Exception ex) { throw new ServletException(ex); } } private SignerSecretProvider constructSecretProvider( boolean fallbackToRandomSecretProvider) throws Exception { SignerSecretProvider provider; String secretProvider = config.getProperty(SIGNER_SECRET_PROVIDER); if (fallbackToRandomSecretProvider && config.getProperty(SIGNATURE_SECRET_FILE) == null) { secretProvider = "random"; } if ("file".equals(secretProvider)) { try { provider = new FileSignerSecretProvider(); provider.init(config, null, tokenValidity); LOG.info("File based secret signer initialized."); } catch (Exception e) { if (fallbackToRandomSecretProvider) { LOG.info("Unable to initialize FileSignerSecretProvider, " + "falling back to use random secrets."); provider = new RandomSignerSecretProvider(); provider.init(config, null, tokenValidity); LOG.info("Random secret signer initialized."); } else { throw new RuntimeException("Can't initialize File based secret signer. Reason: " + e); } } } else if ("random".equals(secretProvider)) { provider = new RandomSignerSecretProvider(); provider.init(config, null, tokenValidity); LOG.info("Random secret signer initialized."); } else { throw new RuntimeException( "Custom secret signer not implemented yet. Use 'file' or 'random'."); } return provider; } /** * This is an empty implementation, it always returns TRUE. * * @param token the authentication token if any, otherwise NULL. * @param request the HTTP client request. * @param response the HTTP client response. * * @return TRUE * @throws IOException it is never thrown. * @throws AuthenticationException it is never thrown. */ public boolean managementOperation(AuthenticationToken token, HttpServletRequest request, HttpServletResponse response) { return true; } /** * Returns the group mapping for the provided user as per Hadoop {@link Groups} Mapping * * @param principals list of principals to file to find group for * @return AuthorizationInfo */ @Override public AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) throws AuthorizationException { Set roles = mapGroupPrincipals(principals.getPrimaryPrincipal().toString()); return new SimpleAuthorizationInfo(roles); } /** * Query the Hadoop implementation of {@link Groups} to retrieve groups for * provided user. */ public Set mapGroupPrincipals(final String mappedPrincipalName) throws AuthorizationException { /* return the groups as seen by Hadoop */ Set groups = null; try { hadoopGroups.refresh(); final List groupList = hadoopGroups.getGroups(mappedPrincipalName); LOG.debug(String.format("group found %s, %s", mappedPrincipalName, groupList.toString())); groups = new HashSet<>(groupList); } catch (final IOException e) { if (e.toString().contains("No groups found for user")) { /* no groups found move on */ LOG.info(String.format("No groups found for user %s", mappedPrincipalName)); } else { /* Log the error and return empty group */ LOG.info(String.format("errorGettingUserGroups for %s", mappedPrincipalName)); throw new AuthorizationException(e); } groups = new HashSet(); } return groups; } /** * This is called when Kerberos authentication is done and a {@link KerberosToken} has * been acquired. * This function returns a Shiro {@link SimpleAccount} based on the {@link KerberosToken} * provided. Null otherwise. */ @Override protected AuthenticationInfo doGetAuthenticationInfo( org.apache.shiro.authc.AuthenticationToken authenticationToken) throws org.apache.shiro.authc.AuthenticationException { if (null != authenticationToken) { KerberosToken kerberosToken = (KerberosToken) authenticationToken; SimpleAccount account = new SimpleAccount(kerberosToken.getPrincipal(), kerberosToken.getCredentials(), kerberosToken.getClass().getName()); account.addRole(mapGroupPrincipals((String)kerberosToken.getPrincipal())); return account; } return null; } /** * If the request has a valid authentication token it allows the request to continue to * the target resource, * otherwise it triggers a GSS-API sequence for authentication * * @param request the request object. * @param response the response object. * @param filterChain the filter chain object. * @throws IOException thrown if an IO error occurred. * @throws ServletException thrown if a processing error occurred. */ public void doKerberosAuth(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { boolean unauthorizedResponse = true; int errCode = HttpServletResponse.SC_UNAUTHORIZED; AuthenticationException authenticationEx = null; HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; boolean isHttps = "https".equals(httpRequest.getScheme()); try { boolean newToken = false; AuthenticationToken token; try { token = getToken(httpRequest); if (LOG.isDebugEnabled()) { LOG.debug("Got token {} from httpRequest {}", token, getRequestURL(httpRequest)); if (null != token) { LOG.debug("token.isExpired() = " + token.isExpired()); } } } catch (AuthenticationException ex) { LOG.warn("AuthenticationToken ignored: " + ex.getMessage()); if (!ex.getMessage().equals("Empty token")) { // will be sent back in a 401 unless filter authenticates authenticationEx = ex; } token = null; } if (managementOperation(token, httpRequest, httpResponse)) { if (token == null || token.isExpired()) { if (LOG.isDebugEnabled()) { LOG.debug("Request [{}] triggering authentication. handler: {}", getRequestURL(httpRequest), this.getClass()); } token = authenticate(httpRequest, httpResponse); if (token != null && token != AuthenticationToken.ANONYMOUS) { // TODO(vr): uncomment when we move to Hadoop 2.8+ // if (token.getMaxInactives() > 0) { // token.setMaxInactives(System.currentTimeMillis() // + getTokenMaxInactiveInterval() * 1000); // } if (token.getExpires() != 0) { token.setExpires(System.currentTimeMillis() + getTokenValidity() * 1000); } } newToken = true; } if (token != null) { unauthorizedResponse = false; if (LOG.isDebugEnabled()) { LOG.debug("Request [{}] user [{}] authenticated", getRequestURL(httpRequest), token.getUserName()); } final AuthenticationToken authToken = token; httpRequest = new HttpServletRequestWrapper(httpRequest) { @Override public String getAuthType() { return authToken.getType(); } @Override public String getRemoteUser() { return authToken.getUserName(); } @Override public Principal getUserPrincipal() { return (authToken != AuthenticationToken.ANONYMOUS) ? authToken : null; } }; // If cookie persistence is configured to false, // it means the cookie will be a session cookie. // If the token is an old one, renew the its tokenMaxInactiveInterval. if (!newToken && !isCookiePersistent() && getTokenMaxInactiveInterval() > 0) { // TODO(vr): uncomment when we move to Hadoop 2.8+ // token.setMaxInactives(System.currentTimeMillis() // + getTokenMaxInactiveInterval() * 1000); token.setExpires(token.getExpires()); newToken = true; } if (newToken && !token.isExpired() && token != AuthenticationToken.ANONYMOUS) { String signedToken = signer.sign(token.toString()); createAuthCookie(httpResponse, signedToken, getCookieDomain(), getCookiePath(), token.getExpires(), isCookiePersistent(), isHttps); } KerberosToken kerberosToken = new KerberosToken(token.getUserName(), token.toString()); SecurityUtils.getSubject().login(kerberosToken); doFilter(filterChain, httpRequest, httpResponse); } } else { if (LOG.isDebugEnabled()) { LOG.debug("managementOperation returned false for request {}." + " token: {}", getRequestURL(httpRequest), token); } unauthorizedResponse = false; } } catch (AuthenticationException ex) { // exception from the filter itself is fatal errCode = HttpServletResponse.SC_FORBIDDEN; authenticationEx = ex; if (LOG.isDebugEnabled()) { LOG.debug("Authentication exception: " + ex.getMessage(), ex); } else { LOG.warn("Authentication exception: " + ex.getMessage()); } } if (unauthorizedResponse) { if (!httpResponse.isCommitted()) { createAuthCookie(httpResponse, "", getCookieDomain(), getCookiePath(), 0, isCookiePersistent(), isHttps); // If response code is 401. Then WWW-Authenticate Header should be // present.. reset to 403 if not found.. if ((errCode == HttpServletResponse.SC_UNAUTHORIZED) && (!httpResponse.containsHeader(KerberosAuthenticator.WWW_AUTHENTICATE))) { errCode = HttpServletResponse.SC_FORBIDDEN; } if (authenticationEx == null) { httpResponse.sendError(errCode, "Authentication required"); } else { httpResponse.sendError(errCode, authenticationEx.getMessage()); } } } } /** * It enforces the the Kerberos SPNEGO authentication sequence returning an * {@link AuthenticationToken} only after the Kerberos SPNEGO sequence has * completed successfully. * * @param request the HTTP client request. * @param response the HTTP client response. * @return an authentication token if the Kerberos SPNEGO sequence is complete * and valid, null if it is in progress (in this case the handler * handles the response to the client). * @throws IOException thrown if an IO error occurred. * @throws AuthenticationException thrown if Kerberos SPNEGO sequence failed. */ public AuthenticationToken authenticate(HttpServletRequest request, final HttpServletResponse response) throws IOException, AuthenticationException { AuthenticationToken token = null; String authorization = request.getHeader( KerberosAuthenticator.AUTHORIZATION); if (authorization == null || !authorization.startsWith(KerberosAuthenticator.NEGOTIATE)) { response.setHeader(KerberosAuthenticator.WWW_AUTHENTICATE, KerberosAuthenticator.NEGOTIATE); response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); if (authorization == null) { LOG.trace("SPNEGO starting for url: {}", request.getRequestURL()); } else { LOG.warn("'" + KerberosAuthenticator.AUTHORIZATION + "' does not start with '" + KerberosAuthenticator.NEGOTIATE + "' : {}", authorization); } } else { authorization = authorization.substring( KerberosAuthenticator.NEGOTIATE.length()).trim(); final Base64 base64 = new Base64(0); final byte[] clientToken = base64.decode(authorization); try { final String serverPrincipal = KerberosUtil.getTokenServerName(clientToken); if (!serverPrincipal.startsWith("HTTP/")) { throw new IllegalArgumentException( "Invalid server principal " + serverPrincipal + "decoded from client request"); } token = Subject.doAs(serverSubject, new PrivilegedExceptionAction() { @Override public AuthenticationToken run() throws Exception { return runWithPrincipal(serverPrincipal, clientToken, base64, response); } }); } catch (PrivilegedActionException ex) { if (ex.getException() instanceof IOException) { throw (IOException) ex.getException(); } else { throw new AuthenticationException(ex.getException()); } } catch (Exception ex) { throw new AuthenticationException(ex); } } return token; } private AuthenticationToken runWithPrincipal(String serverPrincipal, byte[] clientToken, Base64 base64, HttpServletResponse response) throws IOException, GSSException { GSSContext gssContext = null; GSSCredential gssCreds = null; AuthenticationToken token = null; try { LOG.trace("SPNEGO initiated with server principal [{}]", serverPrincipal); gssCreds = this.gssManager.createCredential( this.gssManager.createName(serverPrincipal, KerberosUtil.NT_GSS_KRB5_PRINCIPAL_OID), GSSCredential.INDEFINITE_LIFETIME, new Oid[]{KerberosUtil.GSS_SPNEGO_MECH_OID, KerberosUtil.GSS_KRB5_MECH_OID}, GSSCredential.ACCEPT_ONLY); gssContext = this.gssManager.createContext(gssCreds); byte[] serverToken = gssContext.acceptSecContext(clientToken, 0, clientToken.length); if (serverToken != null && serverToken.length > 0) { String authenticate = base64.encodeToString(serverToken); response.setHeader(KerberosAuthenticator.WWW_AUTHENTICATE, KerberosAuthenticator.NEGOTIATE + " " + authenticate); } if (!gssContext.isEstablished()) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); LOG.trace("SPNEGO in progress"); } else { String clientPrincipal = gssContext.getSrcName().toString(); KerberosName kerberosName = new KerberosName(clientPrincipal); String userName = kerberosName.getShortName(); token = new AuthenticationToken(userName, clientPrincipal, TYPE); response.setStatus(HttpServletResponse.SC_OK); LOG.trace("SPNEGO completed for client principal [{}]", clientPrincipal); } } finally { if (gssContext != null) { gssContext.dispose(); } if (gssCreds != null) { gssCreds.dispose(); } } return token; } /** * Returns the full URL of the request including the query string. *

* Used as a convenience method for logging purposes. * * @param request the request object. * @return the full URL of the request including the query string. */ protected String getRequestURL(HttpServletRequest request) { StringBuffer sb = request.getRequestURL(); if (request.getQueryString() != null) { sb.append("?").append(request.getQueryString()); } return sb.toString(); } /** * Returns the {@link AuthenticationToken} for the request. *

* It looks at the received HTTP cookies and extracts the value of the * {@link AuthenticatedURL#AUTH_COOKIE} * if present. It verifies the signature and if correct it creates the * {@link AuthenticationToken} and returns * it. *

* If this method returns null the filter will invoke the configured * {@link AuthenticationHandler} * to perform user authentication. * * @param request request object. * @return the Authentication token if the request is authenticated, null otherwise. * @throws IOException thrown if an IO error occurred. * @throws AuthenticationException thrown if the token is invalid or if it has expired. */ private AuthenticationToken getToken(HttpServletRequest request) throws AuthenticationException { AuthenticationToken token; Cookie[] cookies = request.getCookies(); token = getTokenFromCookies(cookies); return token; } private static AuthenticationToken getTokenFromCookies(Cookie[] cookies) throws AuthenticationException { AuthenticationToken token = null; String tokenStr = null; if (cookies != null) { for (Cookie cookie : cookies) { if (cookie.getName().equals(AuthenticatedURL.AUTH_COOKIE)) { tokenStr = cookie.getValue(); if (tokenStr.isEmpty()) { throw new AuthenticationException("Empty token"); } try { tokenStr = signer.verifyAndExtract(tokenStr); } catch (SignerException ex) { throw new AuthenticationException(ex); } break; } } } if (tokenStr != null) { token = AuthenticationToken.parse(tokenStr); boolean match = verifyTokenType(token); if (!match) { throw new AuthenticationException("Invalid AuthenticationToken type"); } if (token.isExpired()) { throw new AuthenticationException("AuthenticationToken expired"); } } return token; } /** * A parallel implementation to getTokenFromCookies, this handles * javax.ws.rs.core.HttpHeaders.Cookies kind. * * Used in {@link org.apache.zeppelin.rest.LoginRestApi}::getLogin() * * @param cookies - Cookie(s) map read from HttpHeaders * @return {@link KerberosToken} if available in AUTHORIZATION cookie * * @throws org.apache.shiro.authc.AuthenticationException */ public static KerberosToken getKerberosTokenFromCookies( Map cookies) throws org.apache.shiro.authc.AuthenticationException { KerberosToken kerberosToken = null; String tokenStr = null; if (cookies != null) { for (javax.ws.rs.core.Cookie cookie : cookies.values()) { if (cookie.getName().equals(KerberosAuthenticator.AUTHORIZATION)) { tokenStr = cookie.getValue(); if (tokenStr.isEmpty()) { throw new org.apache.shiro.authc.AuthenticationException("Empty token"); } try { tokenStr = tokenStr.substring(KerberosAuthenticator.NEGOTIATE.length()).trim(); } catch (Exception ex) { throw new org.apache.shiro.authc.AuthenticationException(ex); } break; } } } if (tokenStr != null) { try { AuthenticationToken authToken = AuthenticationToken.parse(tokenStr); boolean match = verifyTokenType(authToken); if (!match) { throw new org.apache.shiro.authc.AuthenticationException("Invalid AuthenticationToken type"); } if (authToken.isExpired()) { throw new org.apache.shiro.authc.AuthenticationException("AuthenticationToken expired"); } kerberosToken = new KerberosToken(authToken.getUserName(), tokenStr); } catch (AuthenticationException ex) { throw new org.apache.shiro.authc.AuthenticationException(ex); } } return kerberosToken; } /** * This method verifies if the specified token type matches one of the the * token types supported by our Authentication provider : {@link KerberosRealm} * * @param token The token whose type needs to be verified. * @return true If the token type matches one of the supported token types * false Otherwise */ protected static boolean verifyTokenType(AuthenticationToken token) { return TYPE.equals(token.getType()); } /** * Delegates call to the servlet filter chain. Sub-classes my override this * method to perform pre and post tasks. * * @param filterChain the filter chain object. * @param request the request object. * @param response the response object. * @throws IOException thrown if an IO error occurred. * @throws ServletException thrown if a processing error occurred. */ protected void doFilter(FilterChain filterChain, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { filterChain.doFilter(request, response); } /** * Creates the Hadoop authentication HTTP cookie. * * @param resp the response object. * @param token authentication token for the cookie. * @param domain the cookie domain. * @param path the cookie path. * @param expires UNIX timestamp that indicates the expire date of the * cookie. It has no effect if its value < 0. * @param isSecure is the cookie secure? * @param isCookiePersistent whether the cookie is persistent or not. *

* XXX the following code duplicate some logic in Jetty / Servlet API, * because of the fact that Hadoop is stuck at servlet 2.5 and jetty 6 * right now. */ public static void createAuthCookie(HttpServletResponse resp, String token, String domain, String path, long expires, boolean isCookiePersistent, boolean isSecure) { StringBuilder sb = new StringBuilder(AuthenticatedURL.AUTH_COOKIE) .append("="); if (token != null && token.length() > 0) { sb.append("\"").append(token).append("\""); } if (path != null) { sb.append("; Path=").append(path); } if (domain != null) { sb.append("; Domain=").append(domain); } if (expires >= 0 && isCookiePersistent) { Date date = new Date(expires); SimpleDateFormat df = new SimpleDateFormat("EEE, " + "dd-MMM-yyyy HH:mm:ss zzz"); df.setTimeZone(TimeZone.getTimeZone("GMT")); sb.append("; Expires=").append(df.format(date)); } if (isSecure) { sb.append("; Secure"); } sb.append("; HttpOnly"); resp.addHeader("Set-Cookie", sb.toString()); } /** * Returns a {@link Properties} config object after dumping all {@link KerberosRealm} bean * properties received from shiro.ini * */ protected Properties getConfiguration() { Properties props = new Properties(); props.put(COOKIE_DOMAIN, cookieDomain); props.put(COOKIE_PATH, cookiePath); props.put(COOKIE_PERSISTENT, isCookiePersistent); props.put(SIGNER_SECRET_PROVIDER, signatureSecretProvider); props.put(SIGNATURE_SECRET_FILE, signatureSecretFile); props.put(AUTH_TYPE, TYPE); props.put(AUTH_TOKEN_VALIDITY, tokenValidity); props.put(AUTH_TOKEN_MAX_INACTIVE_INTERVAL, tokenMaxInactiveInterval); props.put(PRINCIPAL, principal); props.put(KEYTAB, keytab); props.put(NAME_RULES, nameRules); return props; } /** * Returns the max inactive interval time of the generated tokens. * * @return the max inactive interval time of the generated tokens in seconds. */ protected long getTokenMaxInactiveInterval() { return tokenMaxInactiveInterval / 1000; } /** * Returns the tokenValidity time of the generated tokens. * * @return the tokenValidity time of the generated tokens, in seconds. */ protected long getTokenValidity() { return tokenValidity / 1000; } /** * Returns the cookie domain to use for the HTTP cookie. * * @return the cookie domain to use for the HTTP cookie. */ protected String getCookieDomain() { return cookieDomain; } /** * Returns the cookie path to use for the HTTP cookie. * * @return the cookie path to use for the HTTP cookie. */ protected String getCookiePath() { return cookiePath; } /** * Returns the cookie persistence to use for the HTTP cookie. * * @return the cookie persistence to use for the HTTP cookie. */ public boolean isCookiePersistent() { return isCookiePersistent; } public void setTokenMaxInactiveInterval(long tokenMaxInactiveInterval) { this.tokenMaxInactiveInterval = tokenMaxInactiveInterval * 1000; } public void setTokenValidity(long tokenValidity) { this.tokenValidity = tokenValidity * 1000; } public void setCookieDomain(String cookieDomain) { this.cookieDomain = cookieDomain; } public void setCookiePath(String cookiePath) { this.cookiePath = cookiePath; } public void setCookiePersistent(boolean cookiePersistent) { isCookiePersistent = cookiePersistent; } public String getPrincipal() { return principal; } public void setPrincipal(String principal) { this.principal = principal; } public void setKeytab(String keytab) { this.keytab = keytab; } public String getNameRules() { return nameRules; } public void setNameRules(String nameRules) { this.nameRules = nameRules; } public String getSignatureSecretFile() { return signatureSecretFile; } public void setSignatureSecretFile(String signatureSecretFile) { this.signatureSecretFile = signatureSecretFile; } public String getSignatureSecretProvider() { return signatureSecretProvider; } public void setSignatureSecretProvider(String signatureSecretProvider) { this.signatureSecretProvider = signatureSecretProvider; } /** * Releases any resources initialized by the authentication handler. *

* It destroys the Kerberos context. */ public void destroy() { keytab = null; serverSubject = null; if (secretProvider != null && destroySecretProvider) { secretProvider.destroy(); secretProvider = null; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy