Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 270AB200BC1 for ; Wed, 16 Nov 2016 12:51:02 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id 25BD2160B08; Wed, 16 Nov 2016 11:51:02 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 9DCDA160B13 for ; Wed, 16 Nov 2016 12:51:00 +0100 (CET) Received: (qmail 51779 invoked by uid 500); 16 Nov 2016 11:50:59 -0000 Mailing-List: contact commits-help@ambari.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: ambari-dev@ambari.apache.org Delivered-To: mailing list commits@ambari.apache.org Received: (qmail 51595 invoked by uid 99); 16 Nov 2016 11:50:59 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 16 Nov 2016 11:50:59 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 9D038E2F01; Wed, 16 Nov 2016 11:50:59 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: oleewere@apache.org To: commits@ambari.apache.org Date: Wed, 16 Nov 2016 11:51:01 -0000 Message-Id: <5902264fd5c742cc8e35fa70c8fffa14@git.apache.org> In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [3/3] ambari git commit: AMBARI-18821. Logsearch support KNOX SSO (oleewere) archived-at: Wed, 16 Nov 2016 11:51:02 -0000 AMBARI-18821. Logsearch support KNOX SSO (oleewere) Change-Id: I7d275de0ed17f02234ca290811236b2211653bae Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/02e6251d Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/02e6251d Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/02e6251d Branch: refs/heads/branch-2.5 Commit: 02e6251dc702eef70c2db0f4a43c98d23d494a89 Parents: ce4c0cd Author: oleewere Authored: Thu Nov 10 12:12:04 2016 +0100 Committer: oleewere Committed: Wed Nov 16 12:47:32 2016 +0100 ---------------------------------------------------------------------- .../ambari-logsearch-portal/pom.xml | 6 + .../ambari/logsearch/conf/AuthPropsConfig.java | 62 +++++++ .../ambari/logsearch/conf/SecurityConfig.java | 55 ++++-- .../web/filters/LogsearchJWTFilter.java | 181 +++++++++++++++++++ ...LogsearchSecurityContextFormationFilter.java | 3 +- ...rchUsernamePasswordAuthenticationFilter.java | 1 - .../web/model/JWTAuthenticationToken.java | 53 ++++++ .../configuration/logsearch-properties.xml | 63 +++++++ .../LOGSEARCH/0.5.0/themes/theme.json | 87 ++++++++- ambari-web/app/data/HDP2/site_properties.js | 21 +++ 10 files changed, 515 insertions(+), 17 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/02e6251d/ambari-logsearch/ambari-logsearch-portal/pom.xml ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/pom.xml b/ambari-logsearch/ambari-logsearch-portal/pom.xml index be58732..6bacd23 100755 --- a/ambari-logsearch/ambari-logsearch-portal/pom.xml +++ b/ambari-logsearch/ambari-logsearch-portal/pom.xml @@ -37,6 +37,7 @@ 9.2.11.v20150529 1.5.8 2.0.2.RELEASE + 0.6.0 @@ -767,5 +768,10 @@ freemarker 2.3.20 + + io.jsonwebtoken + jjwt + ${jjwt.version} + http://git-wip-us.apache.org/repos/asf/ambari/blob/02e6251d/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/conf/AuthPropsConfig.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/conf/AuthPropsConfig.java b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/conf/AuthPropsConfig.java index 67ddd1f..54cc10c 100644 --- a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/conf/AuthPropsConfig.java +++ b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/conf/AuthPropsConfig.java @@ -21,6 +21,8 @@ package org.apache.ambari.logsearch.conf; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; +import java.util.List; + @Configuration public class AuthPropsConfig { @@ -38,6 +40,18 @@ public class AuthPropsConfig { private String externalAuthLoginUrl; @Value("${logsearch.login.credentials.file:user_pass.json}") private String credentialsFile; + @Value("${logsearch.auth.jwt.enabled:false}") + private boolean authJwtEnabled; + @Value("${logsearch.auth.jwt.provider_url:}") + private String providedUrl; + @Value("${logsearch.auth.jwt.public_key:}") + private String publicKey; + @Value("${logsearch.auth.jwt.cookie.name:hadoop-jwt}") + private String cookieName; + @Value("${logsearch.auth.jwt.query.param.original_url:originalUrl=}") + private String originalUrlQueryParam; + @Value("#{'${logsearch.auth.jwt.audiances:}'.split(',')}") + private List audiences; public boolean isAuthFileEnabled() { return authFileEnabled; @@ -94,4 +108,52 @@ public class AuthPropsConfig { public void setAuthExternalEnabled(boolean authExternalEnabled) { this.authExternalEnabled = authExternalEnabled; } + + public boolean isAuthJwtEnabled() { + return authJwtEnabled; + } + + public void setAuthJwtEnabled(boolean authJwtEnabled) { + this.authJwtEnabled = authJwtEnabled; + } + + public String getProvidedUrl() { + return providedUrl; + } + + public void setProvidedUrl(String providedUrl) { + this.providedUrl = providedUrl; + } + + public String getPublicKey() { + return publicKey; + } + + public void setPublicKey(String publicKey) { + this.publicKey = publicKey; + } + + public String getCookieName() { + return cookieName; + } + + public void setCookieName(String cookieName) { + this.cookieName = cookieName; + } + + public String getOriginalUrlQueryParam() { + return originalUrlQueryParam; + } + + public void setOriginalUrlQueryParam(String originalUrlQueryParam) { + this.originalUrlQueryParam = originalUrlQueryParam; + } + + public List getAudiences() { + return audiences; + } + + public void setAudiences(List audiences) { + this.audiences = audiences; + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/02e6251d/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/conf/SecurityConfig.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/conf/SecurityConfig.java b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/conf/SecurityConfig.java index d3db110..7a6c69c 100644 --- a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/conf/SecurityConfig.java +++ b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/conf/SecurityConfig.java @@ -18,11 +18,13 @@ */ package org.apache.ambari.logsearch.conf; +import com.google.common.collect.Lists; import org.apache.ambari.logsearch.web.authenticate.LogsearchAuthFailureHandler; import org.apache.ambari.logsearch.web.authenticate.LogsearchAuthSuccessHandler; import org.apache.ambari.logsearch.web.authenticate.LogsearchLogoutSuccessHandler; import org.apache.ambari.logsearch.web.filters.LogsearchAuthenticationEntryPoint; import org.apache.ambari.logsearch.web.filters.LogsearchKRBAuthenticationFilter; +import org.apache.ambari.logsearch.web.filters.LogsearchJWTFilter; import org.apache.ambari.logsearch.web.filters.LogsearchSecurityContextFormationFilter; import org.apache.ambari.logsearch.web.filters.LogsearchUsernamePasswordAuthenticationFilter; import org.apache.ambari.logsearch.web.security.LogsearchAuthenticationProvider; @@ -34,11 +36,21 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.util.matcher.NegatedRequestMatcher; +import org.springframework.security.web.util.matcher.OrRequestMatcher; +import org.springframework.security.web.util.matcher.RequestMatcher; + +import javax.inject.Inject; +import java.util.List; @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { + @Inject + private AuthPropsConfig authPropsConfig; + @Override protected void configure(HttpSecurity http) throws Exception { http @@ -46,20 +58,10 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { .sessionManagement() .sessionFixation() .newSession() - .sessionCreationPolicy(SessionCreationPolicy.ALWAYS) + .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) .and() .authorizeRequests() - .antMatchers("/login.html").permitAll() - .antMatchers("/styles/**").permitAll() - .antMatchers("/fonts/**").permitAll() - .antMatchers("/fonts/**").permitAll() - .antMatchers("/scripts/**").permitAll() - .antMatchers("/libs/**").permitAll() - .antMatchers("/images/**").permitAll() - .antMatchers("/templates/**").permitAll() - .antMatchers("/favicon.ico").permitAll() - .antMatchers("/api/v1/public/**").permitAll() - .antMatchers("/api/v1/swagger.json").permitAll() + .requestMatchers(requestMatcher()).permitAll() .antMatchers("/**").authenticated() .and() .authenticationProvider(logsearchAuthenticationProvider()) @@ -70,8 +72,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { .authenticationEntryPoint(logsearchAuthenticationEntryPoint()) .and() .addFilterBefore(logsearchUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) - .addFilterBefore(new LogsearchKRBAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) + .addFilterBefore(logsearchKRBAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) .addFilterAfter(securityContextFormationFilter(), FilterSecurityInterceptor.class) + .addFilterBefore(logsearchJwtFilter(), LogsearchSecurityContextFormationFilter.class) .logout() .logoutUrl("/logout.html") .deleteCookies("JSESSIONID") @@ -94,6 +97,15 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { } @Bean + public LogsearchJWTFilter logsearchJwtFilter() throws Exception { + LogsearchJWTFilter filter = new LogsearchJWTFilter(requestMatcher(), authPropsConfig); + filter.setAuthenticationManager(authenticationManagerBean()); + filter.setAuthenticationSuccessHandler(new LogsearchAuthSuccessHandler()); + filter.setAuthenticationFailureHandler(new LogsearchAuthFailureHandler()); + return filter; + } + + @Bean public LogsearchAuthenticationEntryPoint logsearchAuthenticationEntryPoint() { LogsearchAuthenticationEntryPoint entryPoint = new LogsearchAuthenticationEntryPoint("/login.html"); entryPoint.setForceHttps(false); @@ -109,4 +121,21 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { return filter; } + @Bean + public RequestMatcher requestMatcher() { + List matchers = Lists.newArrayList(); + matchers.add(new AntPathRequestMatcher("/login.html")); + matchers.add(new AntPathRequestMatcher("/logout.html")); + matchers.add(new AntPathRequestMatcher("/styles/**")); + matchers.add(new AntPathRequestMatcher("/fonts/**")); + matchers.add(new AntPathRequestMatcher("/scripts/**")); + matchers.add(new AntPathRequestMatcher("/libs/**")); + matchers.add(new AntPathRequestMatcher("/templates/**")); + matchers.add(new AntPathRequestMatcher("/favicon.ico")); + matchers.add(new AntPathRequestMatcher("/api/v1/public/**")); + matchers.add(new AntPathRequestMatcher("/api/v1/swagger.json")); + matchers.add(new AntPathRequestMatcher("/api/v1/swagger.yaml")); + return new OrRequestMatcher(matchers); + } + } http://git-wip-us.apache.org/repos/asf/ambari/blob/02e6251d/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchJWTFilter.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchJWTFilter.java b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchJWTFilter.java new file mode 100644 index 0000000..1bc7231 --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchJWTFilter.java @@ -0,0 +1,181 @@ +/* + * 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.ambari.logsearch.web.filters; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.MalformedJwtException; +import io.jsonwebtoken.SignatureException; +import org.apache.ambari.logsearch.conf.AuthPropsConfig; +import org.apache.ambari.logsearch.web.model.JWTAuthenticationToken; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.authentication.AnonymousAuthenticationToken; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; +import org.springframework.security.web.util.matcher.NegatedRequestMatcher; +import org.springframework.security.web.util.matcher.RequestMatcher; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPublicKey; + +public class LogsearchJWTFilter extends AbstractAuthenticationProcessingFilter { + + private static final Logger LOG = LoggerFactory.getLogger(LogsearchJWTFilter.class); + + private static final String PEM_HEADER = "-----BEGIN CERTIFICATE-----\n"; + private static final String PEM_FOOTER = "\n-----END CERTIFICATE-----"; + + private AuthPropsConfig authPropsConfig; + + public LogsearchJWTFilter(RequestMatcher requestMatcher, AuthPropsConfig authPropsConfig) { + super(new NegatedRequestMatcher(requestMatcher)); + this.authPropsConfig = authPropsConfig; + } + + @Override + public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { + if (StringUtils.isEmpty(authPropsConfig.getProvidedUrl())) { + throw new BadCredentialsException("Authentication provider URL must not be null or empty."); + } + if (StringUtils.isEmpty(authPropsConfig.getPublicKey())) { + throw new BadCredentialsException("Public key for signature validation must be provisioned."); + } + + try { + Claims claims = Jwts + .parser() + .setSigningKey(parseRSAPublicKey(authPropsConfig.getPublicKey())) + .parseClaimsJws(getJWTFromCookie(request)) + .getBody(); + + String userName = claims.getSubject(); + LOG.info("USERNAME: " + userName); + LOG.info("URL = " + request.getRequestURL()); + if (StringUtils.isNotEmpty(claims.getAudience()) && !authPropsConfig.getAudiences().contains(claims.getAudience())) { + throw new IllegalArgumentException(String.format("Audience validation failed. (Not found: %s)", claims.getAudience())); + } + Authentication authentication = new JWTAuthenticationToken(userName, authPropsConfig.getPublicKey()); + authentication.setAuthenticated(true); + SecurityContextHolder.getContext().setAuthentication(authentication); + return authentication; + } catch (ExpiredJwtException | MalformedJwtException | SignatureException | IllegalArgumentException e) { + LOG.info("URL = " + request.getRequestURL()); + LOG.warn("Error during JWT authentication: ", e.getMessage()); + throw new BadCredentialsException(e.getMessage(), e); + } + } + + @Override + public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (!authPropsConfig.isAuthJwtEnabled() || isAuthenticated(authentication)) { + chain.doFilter(req, res); + return; + } + super.doFilter(req, res, chain); + } + + @Override + protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { + super.successfulAuthentication(request, response, chain, authResult); + response.sendRedirect(request.getRequestURL().toString() + getOriginalQueryString(request)); + } + + @Override + protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException { + super.unsuccessfulAuthentication(request, response, failed); + String loginUrl = constructLoginURL(request); + response.sendRedirect(loginUrl); + } + + private String getJWTFromCookie(HttpServletRequest req) { + String serializedJWT = null; + Cookie[] cookies = req.getCookies(); + if (cookies != null) { + for (Cookie cookie : cookies) { + if (authPropsConfig.getCookieName().equals(cookie.getName())) { + LOG.info(authPropsConfig.getCookieName() + " cookie has been found and is being processed"); + serializedJWT = cookie.getValue(); + break; + } + } + } + return serializedJWT; + } + + private RSAPublicKey parseRSAPublicKey(String pem) throws ServletException { + String fullPem = PEM_HEADER + pem + PEM_FOOTER; + try { + CertificateFactory fact = CertificateFactory.getInstance("X.509"); + ByteArrayInputStream is = new ByteArrayInputStream(fullPem.getBytes("UTF8")); + + X509Certificate cer = (X509Certificate) fact.generateCertificate(is); + return (RSAPublicKey) cer.getPublicKey(); + } catch (CertificateException ce) { + String message; + if (pem.startsWith(PEM_HEADER)) { + message = "CertificateException - be sure not to include PEM header " + + "and footer in the PEM configuration element."; + } else { + message = "CertificateException - PEM may be corrupt"; + } + throw new ServletException(message, ce); + } catch (UnsupportedEncodingException uee) { + throw new ServletException(uee); + } + } + + private String constructLoginURL(HttpServletRequest request) { + String delimiter = "?"; + if (authPropsConfig.getProvidedUrl().contains("?")) { + delimiter = "&"; + } + return authPropsConfig.getProvidedUrl() + delimiter + + authPropsConfig.getOriginalUrlQueryParam() + "=" + + request.getRequestURL().toString() + getOriginalQueryString(request); + } + + private String getOriginalQueryString(HttpServletRequest request) { + String originalQueryString = request.getQueryString(); + return (originalQueryString == null) ? "" : "?" + originalQueryString; + } + + private boolean isAuthenticated(Authentication authentication) { + return authentication != null && !(authentication instanceof AnonymousAuthenticationToken) && authentication.isAuthenticated(); + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/02e6251d/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchSecurityContextFormationFilter.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchSecurityContextFormationFilter.java b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchSecurityContextFormationFilter.java index 1320278..b427749 100644 --- a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchSecurityContextFormationFilter.java +++ b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchSecurityContextFormationFilter.java @@ -88,8 +88,7 @@ public class LogsearchSecurityContextFormationFilter extends GenericFilterBean { httpResponse.addCookie(cookie); } // [1]get the context from session - LogSearchContext context = (LogSearchContext) httpSession - .getAttribute(LOGSEARCH_SC_SESSION_KEY); + LogSearchContext context = (LogSearchContext) httpSession.getAttribute(LOGSEARCH_SC_SESSION_KEY); if (context == null) { context = new LogSearchContext(); httpSession.setAttribute(LOGSEARCH_SC_SESSION_KEY, context); http://git-wip-us.apache.org/repos/asf/ambari/blob/02e6251d/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchUsernamePasswordAuthenticationFilter.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchUsernamePasswordAuthenticationFilter.java b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchUsernamePasswordAuthenticationFilter.java index 85688a2..24ec2d4 100644 --- a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchUsernamePasswordAuthenticationFilter.java +++ b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchUsernamePasswordAuthenticationFilter.java @@ -36,7 +36,6 @@ public class LogsearchUsernamePasswordAuthenticationFilter extends UsernamePassw public void setRememberMeServices(RememberMeServices rememberMeServices) { super.setRememberMeServices(rememberMeServices); - } @Override http://git-wip-us.apache.org/repos/asf/ambari/blob/02e6251d/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/model/JWTAuthenticationToken.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/model/JWTAuthenticationToken.java b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/model/JWTAuthenticationToken.java new file mode 100644 index 0000000..35175b6 --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/model/JWTAuthenticationToken.java @@ -0,0 +1,53 @@ +/* + * 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.ambari.logsearch.web.model; + +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; + +import java.util.Collection; + +public class JWTAuthenticationToken extends AbstractAuthenticationToken { + + private String credential; + + private String principal; + + public JWTAuthenticationToken(String principal, String credential) { + super((Collection)null); + this.principal = principal; + this.credential = credential; + } + + public JWTAuthenticationToken(String principal, String credential, Collection authorities) { + super(authorities); + this.principal = principal; + this.credential = credential; + } + + @Override + public Object getCredentials() { + return credential; + } + + @Override + public Object getPrincipal() { + return principal; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/02e6251d/ambari-server/src/main/resources/common-services/LOGSEARCH/0.5.0/configuration/logsearch-properties.xml ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/common-services/LOGSEARCH/0.5.0/configuration/logsearch-properties.xml b/ambari-server/src/main/resources/common-services/LOGSEARCH/0.5.0/configuration/logsearch-properties.xml index febeffd..9dcd5cf 100644 --- a/ambari-server/src/main/resources/common-services/LOGSEARCH/0.5.0/configuration/logsearch-properties.xml +++ b/ambari-server/src/main/resources/common-services/LOGSEARCH/0.5.0/configuration/logsearch-properties.xml @@ -173,4 +173,67 @@ The path and query of the external server used to authenticate + + logsearch.auth.jwt.enabled + false + JWT authentication enabled + Enable JWT based authentication for Log Search portal + + value-list + false + + + true + + + + false + + + + 1 + + + + + logsearch.auth.jwt.provider_url + + JWT authentication provider url + URL to the JWT authentication server + + + + logsearch.auth.jwt.query.param.original_url + originalUrl + JWT original url query param + Name of the original request URL which is used to redirect to Log Search Portal + + + + logsearch.auth.jwt.cookie.name + hadoop-jwt + JWT cookie name + The name of the cookie that contains the JWT token + + + + logsearch.auth.jwt.audiances + + JWT expected audiances + Comma separated list of acceptable audiences for the JWT token + + true + + + + + logsearch.auth.jwt.public_key + + JWT authentication signing key + PEM formatted public key for JWT token without the header and the footer + + content + + + http://git-wip-us.apache.org/repos/asf/ambari/blob/02e6251d/ambari-server/src/main/resources/common-services/LOGSEARCH/0.5.0/themes/theme.json ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/common-services/LOGSEARCH/0.5.0/themes/theme.json b/ambari-server/src/main/resources/common-services/LOGSEARCH/0.5.0/themes/theme.json index 2ed6474..0193689 100644 --- a/ambari-server/src/main/resources/common-services/LOGSEARCH/0.5.0/themes/theme.json +++ b/ambari-server/src/main/resources/common-services/LOGSEARCH/0.5.0/themes/theme.json @@ -11,7 +11,7 @@ "display-name": "Settings", "layout": { "tab-columns": "2", - "tab-rows": "1", + "tab-rows": "2", "sections": [ { "name": "section-logsearch-server", @@ -38,6 +38,25 @@ "column-span": "1" } ] + }, + { + "name": "section-logsearch-sso", + "display-name": "Single Sign-On", + "row-index": "1", + "column-index": "1", + "row-span": "3", + "column-span": "1", + "section-columns": "1", + "section-rows": "5", + "subsections": [ + { + "name": "subsection-logsearch-server-sso-col1", + "row-index": "1", + "column-index": "0", + "row-span": "3", + "column-span": "1" + } + ] } ] } @@ -71,6 +90,54 @@ { "config": "logsearch-properties/logsearch.collection.audit.logs.replication.factor", "subsection-name": "subsection-logsearch-server-col2" + }, + { + "config": "logsearch-properties/logsearch.auth.jwt.enabled", + "subsection-name": "subsection-logsearch-server-sso-col1" + }, + { + "config": "logsearch-properties/logsearch.auth.jwt.provider_url", + "subsection-name": "subsection-logsearch-server-sso-col1", + "depends-on": [ + { + "configs":[ + "logsearch-properties/logsearch.auth.jwt.enabled" + ], + "if": "${logsearch-properties/logsearch.auth.jwt.enabled}", + "then": { + "property_value_attributes": { + "visible": true + } + }, + "else": { + "property_value_attributes": { + "visible": false + } + } + } + ] + }, + { + "config": "logsearch-properties/logsearch.auth.jwt.public_key", + "subsection-name": "subsection-logsearch-server-sso-col1", + "depends-on": [ + { + "configs":[ + "logsearch-properties/logsearch.auth.jwt.enabled" + ], + "if": "${logsearch-properties/logsearch.auth.jwt.enabled}", + "then": { + "property_value_attributes": { + "visible": true + } + }, + "else": { + "property_value_attributes": { + "visible": false + } + } + } + ] } ] }, @@ -135,6 +202,24 @@ } ] } + }, + { + "config": "logsearch-properties/logsearch.auth.jwt.enabled", + "widget": { + "type": "toggle" + } + }, + { + "config": "logsearch-properties/logsearch.auth.jwt.provider_url", + "widget": { + "type": "text-field" + } + }, + { + "config": "logsearch-properties/logsearch.auth.jwt.public_key", + "widget": { + "type": "directories" + } } ] } http://git-wip-us.apache.org/repos/asf/ambari/blob/02e6251d/ambari-web/app/data/HDP2/site_properties.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/data/HDP2/site_properties.js b/ambari-web/app/data/HDP2/site_properties.js index 5be3b5a..d61d4aa 100644 --- a/ambari-web/app/data/HDP2/site_properties.js +++ b/ambari-web/app/data/HDP2/site_properties.js @@ -2264,6 +2264,27 @@ var hdp2properties = [ "category": "Advanced logsearch-properties", "index": 11 }, + { + "name": "logsearch.auth.jwt.audiances", + "serviceName": "LOGSEARCH", + "filename": "logsearch-properties.xml", + "category": "Advanced logsearch-properties", + "index": 12 + }, + { + "name": "logsearch.auth.jwt.cookie.name", + "serviceName": "LOGSEARCH", + "filename": "logsearch-properties.xml", + "category": "Advanced logsearch-properties", + "index": 13 + }, + { + "name": "logsearch.auth.jwt.query.param.original_url", + "serviceName": "LOGSEARCH", + "filename": "logsearch-properties.xml", + "category": "Advanced logsearch-properties", + "index": 14 + }, /*infra-solr-client-log4j*/ { "name": "infra_solr_client_log_dir",