mirror of https://github.com/apache/nifi.git
NIFI-13295 Removed Apache Knox SSO Authentication
This closes #8876 Signed-off-by: Joseph Witt <joewitt@apache.org>
This commit is contained in:
parent
43cc2b4aaa
commit
fa8dc4f1a0
|
@ -39,7 +39,6 @@ import java.util.Map;
|
|||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* The NiFiProperties class holds all properties which are needed for various
|
||||
|
@ -181,12 +180,6 @@ public class NiFiProperties extends ApplicationProperties {
|
|||
public static final String SECURITY_USER_OIDC_FALLBACK_CLAIMS_IDENTIFYING_USER = "nifi.security.user.oidc.fallback.claims.identifying.user";
|
||||
public static final String SECURITY_USER_OIDC_TOKEN_REFRESH_WINDOW = "nifi.security.user.oidc.token.refresh.window";
|
||||
|
||||
// apache knox
|
||||
public static final String SECURITY_USER_KNOX_URL = "nifi.security.user.knox.url";
|
||||
public static final String SECURITY_USER_KNOX_PUBLIC_KEY = "nifi.security.user.knox.publicKey";
|
||||
public static final String SECURITY_USER_KNOX_COOKIE_NAME = "nifi.security.user.knox.cookieName";
|
||||
public static final String SECURITY_USER_KNOX_AUDIENCES = "nifi.security.user.knox.audiences";
|
||||
|
||||
// saml
|
||||
public static final String SECURITY_USER_SAML_IDP_METADATA_URL = "nifi.security.user.saml.idp.metadata.url";
|
||||
public static final String SECURITY_USER_SAML_SP_ENTITY_ID = "nifi.security.user.saml.sp.entity.id";
|
||||
|
@ -1149,57 +1142,6 @@ public class NiFiProperties extends ApplicationProperties {
|
|||
return getProperty(DIAGNOSTICS_ON_SHUTDOWN_MAX_DIRECTORY_SIZE, DEFAULT_DIAGNOSTICS_ON_SHUTDOWN_MAX_DIRECTORY_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether Knox SSO is enabled.
|
||||
*
|
||||
* @return whether Knox SSO is enabled
|
||||
*/
|
||||
public boolean isKnoxSsoEnabled() {
|
||||
return !StringUtils.isBlank(getKnoxUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Knox URL.
|
||||
*
|
||||
* @return Knox URL
|
||||
*/
|
||||
public String getKnoxUrl() {
|
||||
return getProperty(SECURITY_USER_KNOX_URL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the configured Knox Audiences.
|
||||
*
|
||||
* @return Knox audiences
|
||||
*/
|
||||
public Set<String> getKnoxAudiences() {
|
||||
final String rawAudiences = getProperty(SECURITY_USER_KNOX_AUDIENCES);
|
||||
if (StringUtils.isBlank(rawAudiences)) {
|
||||
return null;
|
||||
} else {
|
||||
final String[] audienceTokens = rawAudiences.split(",");
|
||||
return Stream.of(audienceTokens).map(String::trim).filter(aud -> !StringUtils.isEmpty(aud)).collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to the Knox public key.
|
||||
*
|
||||
* @return path to the Knox public key
|
||||
*/
|
||||
public Path getKnoxPublicKeyPath() {
|
||||
return Paths.get(getProperty(SECURITY_USER_KNOX_PUBLIC_KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the Knox cookie.
|
||||
*
|
||||
* @return name of the Knox cookie
|
||||
*/
|
||||
public String getKnoxCookieName() {
|
||||
return getProperty(SECURITY_USER_KNOX_COOKIE_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether SAML is enabled.
|
||||
*
|
||||
|
@ -1354,7 +1296,6 @@ public class NiFiProperties extends ApplicationProperties {
|
|||
* - login identity provider is not populated
|
||||
* - Kerberos service support is not enabled
|
||||
* - openid connect is not enabled
|
||||
* - knox sso is not enabled
|
||||
* - anonymous authentication is not enabled
|
||||
* </p>
|
||||
*
|
||||
|
@ -1363,7 +1304,6 @@ public class NiFiProperties extends ApplicationProperties {
|
|||
public boolean isClientAuthRequiredForRestApi() {
|
||||
return !isLoginIdentityProviderEnabled()
|
||||
&& !isOidcEnabled()
|
||||
&& !isKnoxSsoEnabled()
|
||||
&& !isSamlEnabled()
|
||||
&& !isAnonymousAuthenticationAllowed();
|
||||
}
|
||||
|
|
|
@ -347,9 +347,6 @@ used. The default value of this property is `single-user-provider` supporting au
|
|||
For Single sign-on authentication, NiFi will redirect users to the Identity Provider before returning to NiFi. NiFi will then
|
||||
process responses and convert attributes to application token information.
|
||||
|
||||
During Apache Knox authentication, NiFi will redirect users to login with Apache Knox before returning to NiFi. NiFi will verify the Apache Knox
|
||||
token during authentication.
|
||||
|
||||
NOTE: NiFi cannot be configured for multiple authentication strategies simultaneously.
|
||||
NiFi will require client certificates for authenticating users over HTTPS if no other strategies have been configured.
|
||||
|
||||
|
@ -638,21 +635,6 @@ SAML authentication enables the following REST API resources for integration wit
|
|||
| /nifi-api/access/saml/single-logout/request | Complete SAML 2.0 Single Logout processing initiating a request to the Asserting Party. Requires Single Logout to be enabled.
|
||||
|======================================
|
||||
|
||||
[[apache_knox]]
|
||||
=== Apache Knox
|
||||
|
||||
To enable authentication via Apache Knox the following properties must be configured in _nifi.properties_.
|
||||
|
||||
[options="header"]
|
||||
|==================================================================================================================================================
|
||||
| Property Name | Description
|
||||
|`nifi.security.user.knox.url` | The URL for the Apache Knox login page.
|
||||
|`nifi.security.user.knox.publicKey` | The path to the Apache Knox public key that will be used to verify the signatures of the authentication tokens in the HTTP Cookie.
|
||||
|`nifi.security.user.knox.cookieName` | The name of the HTTP Cookie that Apache Knox will generate after successful login. The default value is `hadoop-jwt`.
|
||||
|`nifi.security.user.knox.audiences` | Optional. A comma separate listed of allowed audiences. If set, the audience in the token must be present in
|
||||
this listing. The audience that is populated in the token can be configured in Knox.
|
||||
|==================================================================================================================================================
|
||||
|
||||
[[json_web_token]]
|
||||
=== JSON Web Tokens
|
||||
|
||||
|
|
|
@ -250,11 +250,6 @@ public class ThreadPoolRequestReplicator implements RequestReplicator {
|
|||
// remove the access token if present, since the user is already authenticated... authorization
|
||||
// will happen when the request is replicated using the proxy chain above
|
||||
removeHeader(headers, SecurityHeader.AUTHORIZATION.getHeader());
|
||||
|
||||
// if knox sso cookie name is set, remove any authentication cookie since this user is already authenticated
|
||||
// and will be included in the proxied entities chain above... authorization will happen when the
|
||||
// request is replicated
|
||||
removeCookie(headers, nifiProperties.getKnoxCookieName());
|
||||
removeCookie(headers, SecurityCookieName.AUTHORIZATION_BEARER.getName());
|
||||
removeCookie(headers, SecurityCookieName.REQUEST_TOKEN.getName());
|
||||
|
||||
|
|
|
@ -174,12 +174,6 @@
|
|||
<nifi.security.user.oidc.truststore.strategy>JDK</nifi.security.user.oidc.truststore.strategy>
|
||||
<nifi.security.user.oidc.token.refresh.window>60 secs</nifi.security.user.oidc.token.refresh.window>
|
||||
|
||||
<!-- nifi.properties: apache knox -->
|
||||
<nifi.security.user.knox.url />
|
||||
<nifi.security.user.knox.publicKey />
|
||||
<nifi.security.user.knox.cookieName>hadoop-jwt</nifi.security.user.knox.cookieName>
|
||||
<nifi.security.user.knox.audiences />
|
||||
|
||||
<!-- nifi.properties: saml -->
|
||||
<nifi.security.user.saml.idp.metadata.url />
|
||||
<nifi.security.user.saml.sp.entity.id />
|
||||
|
|
|
@ -219,12 +219,6 @@ nifi.security.user.oidc.claim.groups=${nifi.security.user.oidc.claim.groups}
|
|||
nifi.security.user.oidc.truststore.strategy=${nifi.security.user.oidc.truststore.strategy}
|
||||
nifi.security.user.oidc.token.refresh.window=${nifi.security.user.oidc.token.refresh.window}
|
||||
|
||||
# Apache Knox SSO Properties #
|
||||
nifi.security.user.knox.url=${nifi.security.user.knox.url}
|
||||
nifi.security.user.knox.publicKey=${nifi.security.user.knox.publicKey}
|
||||
nifi.security.user.knox.cookieName=${nifi.security.user.knox.cookieName}
|
||||
nifi.security.user.knox.audiences=${nifi.security.user.knox.audiences}
|
||||
|
||||
# SAML Properties #
|
||||
nifi.security.user.saml.idp.metadata.url=${nifi.security.user.saml.idp.metadata.url}
|
||||
nifi.security.user.saml.sp.entity.id=${nifi.security.user.saml.sp.entity.id}
|
||||
|
|
|
@ -284,7 +284,6 @@ public class JettyServer implements NiFiServer, ExtensionUiLoader {
|
|||
// load the web ui app
|
||||
final WebAppContext webUiContext = loadWar(webUiWar, CONTEXT_PATH_NIFI, frameworkClassLoader);
|
||||
webUiContext.getInitParams().put("oidc-supported", String.valueOf(props.isOidcEnabled()));
|
||||
webUiContext.getInitParams().put("knox-supported", String.valueOf(props.isKnoxSsoEnabled()));
|
||||
webUiContext.getInitParams().put("saml-supported", String.valueOf(props.isSamlEnabled()));
|
||||
webUiContext.getInitParams().put("saml-single-logout-supported", String.valueOf(props.isSamlSingleLogoutEnabled()));
|
||||
webAppContextHandlers.addHandler(webUiContext);
|
||||
|
@ -311,7 +310,6 @@ public class JettyServer implements NiFiServer, ExtensionUiLoader {
|
|||
if (webNewUiWar != null) {
|
||||
final WebAppContext newUiContext = loadWar(webNewUiWar, CONTEXT_PATH_NF, frameworkClassLoader);
|
||||
newUiContext.getInitParams().put("oidc-supported", String.valueOf(props.isOidcEnabled()));
|
||||
newUiContext.getInitParams().put("knox-supported", String.valueOf(props.isKnoxSsoEnabled()));
|
||||
newUiContext.getInitParams().put("saml-supported", String.valueOf(props.isSamlEnabled()));
|
||||
newUiContext.getInitParams().put("saml-single-logout-supported", String.valueOf(props.isSamlSingleLogoutEnabled()));
|
||||
webAppContextHandlers.addHandler(newUiContext);
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
*/
|
||||
package org.apache.nifi.web.api;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.time.Instant;
|
||||
|
@ -42,7 +41,6 @@ import jakarta.ws.rs.Produces;
|
|||
import jakarta.ws.rs.core.Context;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.UriBuilder;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.admin.service.AdministrationException;
|
||||
import org.apache.nifi.authentication.AuthenticationResponse;
|
||||
|
@ -69,7 +67,6 @@ import org.apache.nifi.web.security.UntrustedProxyException;
|
|||
import org.apache.nifi.web.security.cookie.ApplicationCookieName;
|
||||
import org.apache.nifi.web.security.jwt.provider.BearerTokenProvider;
|
||||
import org.apache.nifi.web.security.jwt.revocation.JwtLogoutListener;
|
||||
import org.apache.nifi.web.security.knox.KnoxService;
|
||||
import org.apache.nifi.web.security.logout.LogoutRequest;
|
||||
import org.apache.nifi.web.security.logout.LogoutRequestManager;
|
||||
import org.apache.nifi.web.security.token.LoginAuthenticationToken;
|
||||
|
@ -108,7 +105,6 @@ public class AccessResource extends ApplicationResource {
|
|||
private JwtDecoder jwtDecoder;
|
||||
private BearerTokenProvider bearerTokenProvider;
|
||||
private BearerTokenResolver bearerTokenResolver;
|
||||
private KnoxService knoxService;
|
||||
private LogoutRequestManager logoutRequestManager;
|
||||
|
||||
/**
|
||||
|
@ -140,74 +136,6 @@ public class AccessResource extends ApplicationResource {
|
|||
return generateOkResponse(entity).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Consumes(MediaType.WILDCARD)
|
||||
@Produces(MediaType.WILDCARD)
|
||||
@Path("knox/request")
|
||||
@Operation(
|
||||
summary = "Initiates a request to authenticate through Apache Knox."
|
||||
)
|
||||
public void knoxRequest(@Context HttpServletRequest httpServletRequest, @Context HttpServletResponse httpServletResponse) throws Exception {
|
||||
// only consider user specific access over https
|
||||
if (!httpServletRequest.isSecure()) {
|
||||
httpServletResponse.sendError(HttpURLConnection.HTTP_NOT_ACCEPTABLE, AUTHENTICATION_NOT_ENABLED_MSG);
|
||||
return;
|
||||
}
|
||||
|
||||
// ensure knox is enabled
|
||||
if (!knoxService.isKnoxEnabled()) {
|
||||
httpServletResponse.sendError(HttpURLConnection.HTTP_NOT_ACCEPTABLE, "Apache Knox SSO support is not configured.");
|
||||
return;
|
||||
}
|
||||
|
||||
// build the originalUri, and direct back to the ui
|
||||
final String originalUri = generateResourceUri("access", "knox", "callback");
|
||||
|
||||
// build the authorization uri
|
||||
final URI authorizationUri = UriBuilder.fromUri(knoxService.getKnoxUrl())
|
||||
.queryParam("originalUrl", originalUri)
|
||||
.build();
|
||||
|
||||
// generate the response
|
||||
httpServletResponse.sendRedirect(authorizationUri.toString());
|
||||
}
|
||||
|
||||
@GET
|
||||
@Consumes(MediaType.WILDCARD)
|
||||
@Produces(MediaType.WILDCARD)
|
||||
@Path("knox/callback")
|
||||
@Operation(
|
||||
summary = "Redirect/callback URI for processing the result of the Apache Knox login sequence."
|
||||
)
|
||||
public void knoxCallback(@Context HttpServletRequest httpServletRequest, @Context HttpServletResponse httpServletResponse) throws Exception {
|
||||
// only consider user specific access over https
|
||||
if (!httpServletRequest.isSecure()) {
|
||||
httpServletResponse.sendError(HttpURLConnection.HTTP_NOT_ACCEPTABLE, AUTHENTICATION_NOT_ENABLED_MSG);
|
||||
return;
|
||||
}
|
||||
|
||||
// ensure knox is enabled
|
||||
if (!knoxService.isKnoxEnabled()) {
|
||||
httpServletResponse.sendError(HttpURLConnection.HTTP_NOT_ACCEPTABLE, "Apache Knox SSO support is not configured.");
|
||||
return;
|
||||
}
|
||||
|
||||
httpServletResponse.sendRedirect(getNiFiUri());
|
||||
}
|
||||
|
||||
@GET
|
||||
@Consumes(MediaType.WILDCARD)
|
||||
@Produces(MediaType.WILDCARD)
|
||||
@Path("knox/logout")
|
||||
@Operation(
|
||||
summary = "Performs a logout in the Apache Knox.",
|
||||
description = NON_GUARANTEED_ENDPOINT
|
||||
)
|
||||
public void knoxLogout(@Context HttpServletResponse httpServletResponse) throws Exception {
|
||||
String redirectPath = generateResourceUri("..", "nifi", "login");
|
||||
httpServletResponse.sendRedirect(redirectPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status the client's access.
|
||||
*
|
||||
|
@ -542,10 +470,6 @@ public class AccessResource extends ApplicationResource {
|
|||
this.certificateExtractor = certificateExtractor;
|
||||
}
|
||||
|
||||
public void setKnoxService(KnoxService knoxService) {
|
||||
this.knoxService = knoxService;
|
||||
}
|
||||
|
||||
public void setLogoutRequestManager(LogoutRequestManager logoutRequestManager) {
|
||||
this.logoutRequestManager = logoutRequestManager;
|
||||
}
|
||||
|
|
|
@ -607,7 +607,6 @@
|
|||
<bean id="accessResource" class="org.apache.nifi.web.api.AccessResource" scope="singleton">
|
||||
<property name="logoutRequestManager" ref="logoutRequestManager" />
|
||||
<property name="loginIdentityProvider" ref="loginIdentityProvider"/>
|
||||
<property name="knoxService" ref="knoxService"/>
|
||||
<property name="x509AuthenticationProvider" ref="x509AuthenticationProvider"/>
|
||||
<property name="certificateExtractor" ref="certificateExtractor"/>
|
||||
<property name="principalExtractor" ref="principalExtractor"/>
|
||||
|
|
|
@ -37,7 +37,6 @@ import org.springframework.security.authentication.AuthenticationManager;
|
|||
ClientRegistrationConfiguration.class,
|
||||
JwtAuthenticationSecurityConfiguration.class,
|
||||
JwtDecoderConfiguration.class,
|
||||
KnoxAuthenticationSecurityConfiguration.class,
|
||||
OidcSecurityConfiguration.class,
|
||||
SamlAuthenticationSecurityConfiguration.class,
|
||||
X509AuthenticationSecurityConfiguration.class
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* 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.nifi.web.security.configuration;
|
||||
|
||||
import org.apache.nifi.authorization.Authorizer;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.apache.nifi.web.security.knox.KnoxAuthenticationFilter;
|
||||
import org.apache.nifi.web.security.knox.KnoxAuthenticationProvider;
|
||||
import org.apache.nifi.web.security.knox.KnoxService;
|
||||
import org.apache.nifi.web.security.knox.KnoxServiceFactoryBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
|
||||
/**
|
||||
* Knox Configuration for Authentication Security
|
||||
*/
|
||||
@Configuration
|
||||
public class KnoxAuthenticationSecurityConfiguration {
|
||||
private final NiFiProperties niFiProperties;
|
||||
|
||||
private final Authorizer authorizer;
|
||||
|
||||
@Autowired
|
||||
public KnoxAuthenticationSecurityConfiguration(
|
||||
final NiFiProperties niFiProperties,
|
||||
final Authorizer authorizer
|
||||
) {
|
||||
this.niFiProperties = niFiProperties;
|
||||
this.authorizer = authorizer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KnoxAuthenticationFilter knoxAuthenticationFilter(final AuthenticationManager authenticationManager) {
|
||||
final KnoxAuthenticationFilter knoxAuthenticationFilter = new KnoxAuthenticationFilter();
|
||||
knoxAuthenticationFilter.setAuthenticationManager(authenticationManager);
|
||||
knoxAuthenticationFilter.setProperties(niFiProperties);
|
||||
return knoxAuthenticationFilter;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KnoxAuthenticationProvider knoxAuthenticationProvider() {
|
||||
return new KnoxAuthenticationProvider(knoxService(), niFiProperties, authorizer);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KnoxService knoxService() {
|
||||
final KnoxServiceFactoryBean knoxServiceFactoryBean = new KnoxServiceFactoryBean();
|
||||
knoxServiceFactoryBean.setProperties(niFiProperties);
|
||||
return knoxServiceFactoryBean.getObject();
|
||||
}
|
||||
}
|
|
@ -24,7 +24,6 @@ import org.apache.nifi.web.security.csrf.CsrfCookieRequestMatcher;
|
|||
import org.apache.nifi.web.security.csrf.SkipReplicatedCsrfFilter;
|
||||
import org.apache.nifi.web.security.csrf.StandardCookieCsrfTokenRepository;
|
||||
import org.apache.nifi.web.security.csrf.StandardCsrfTokenRequestAttributeHandler;
|
||||
import org.apache.nifi.web.security.knox.KnoxAuthenticationFilter;
|
||||
import org.apache.nifi.web.security.log.AuthenticationUserFilter;
|
||||
import org.apache.nifi.web.security.oidc.client.web.OidcBearerTokenRefreshFilter;
|
||||
import org.apache.nifi.web.security.oidc.logout.OidcLogoutFilter;
|
||||
|
@ -87,7 +86,6 @@ public class WebSecurityConfiguration {
|
|||
final StandardAuthenticationEntryPoint authenticationEntryPoint,
|
||||
final X509AuthenticationFilter x509AuthenticationFilter,
|
||||
final BearerTokenAuthenticationFilter bearerTokenAuthenticationFilter,
|
||||
final KnoxAuthenticationFilter knoxAuthenticationFilter,
|
||||
final NiFiAnonymousAuthenticationFilter anonymousAuthenticationFilter,
|
||||
final OAuth2LoginAuthenticationFilter oAuth2LoginAuthenticationFilter,
|
||||
final OAuth2AuthorizationCodeGrantFilter oAuth2AuthorizationCodeGrantFilter,
|
||||
|
@ -115,8 +113,6 @@ public class WebSecurityConfiguration {
|
|||
"/access",
|
||||
"/access/config",
|
||||
"/access/token",
|
||||
"/access/knox/callback",
|
||||
"/access/knox/request",
|
||||
"/access/logout/complete",
|
||||
"/authentication/configuration"
|
||||
).permitAll()
|
||||
|
@ -140,10 +136,6 @@ public class WebSecurityConfiguration {
|
|||
.addFilterBefore(bearerTokenAuthenticationFilter, AnonymousAuthenticationFilter.class)
|
||||
.addFilterBefore(new AuthenticationUserFilter(), ExceptionTranslationFilter.class);
|
||||
|
||||
if (properties.isKnoxSsoEnabled()) {
|
||||
http.addFilterBefore(knoxAuthenticationFilter, AnonymousAuthenticationFilter.class);
|
||||
}
|
||||
|
||||
if (properties.isAnonymousAuthenticationAllowed() || properties.isHttpEnabled()) {
|
||||
http.addFilterAfter(anonymousAuthenticationFilter, AnonymousAuthenticationFilter.class);
|
||||
}
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* 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.nifi.web.security.knox;
|
||||
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.apache.nifi.web.security.NiFiAuthenticationFilter;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
import jakarta.servlet.http.Cookie;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class KnoxAuthenticationFilter extends NiFiAuthenticationFilter {
|
||||
|
||||
@Override
|
||||
public Authentication attemptAuthentication(final HttpServletRequest request) {
|
||||
// only support knox login when running securely
|
||||
if (!request.isSecure()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// ensure knox sso support is enabled
|
||||
final NiFiProperties properties = getProperties();
|
||||
if (!properties.isKnoxSsoEnabled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// get the principal out of the user token
|
||||
final String knoxJwt = getJwtFromCookie(request, properties.getKnoxCookieName());
|
||||
|
||||
// if there is no cookie, return null to attempt another authentication
|
||||
if (knoxJwt == null) {
|
||||
return null;
|
||||
} else {
|
||||
// otherwise create the authentication request token
|
||||
return new KnoxAuthenticationRequestToken(knoxJwt, request.getRemoteAddr());
|
||||
}
|
||||
}
|
||||
|
||||
public String getJwtFromCookie(final HttpServletRequest request, final String cookieName) {
|
||||
String jwt = null;
|
||||
|
||||
final Cookie[] cookies = request.getCookies();
|
||||
if (cookies != null) {
|
||||
for (Cookie cookie : cookies) {
|
||||
if (cookieName.equals(cookie.getName())) {
|
||||
jwt = cookie.getValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return jwt;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* 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.nifi.web.security.knox;
|
||||
|
||||
import com.nimbusds.jose.JOSEException;
|
||||
import org.apache.nifi.authorization.Authorizer;
|
||||
import org.apache.nifi.authorization.user.NiFiUser;
|
||||
import org.apache.nifi.authorization.user.NiFiUserDetails;
|
||||
import org.apache.nifi.authorization.user.StandardNiFiUser.Builder;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.apache.nifi.web.security.InvalidAuthenticationException;
|
||||
import org.apache.nifi.web.security.NiFiAuthenticationProvider;
|
||||
import org.apache.nifi.web.security.token.NiFiAuthenticationToken;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
|
||||
import java.text.ParseException;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class KnoxAuthenticationProvider extends NiFiAuthenticationProvider {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(KnoxAuthenticationProvider.class);
|
||||
|
||||
private final KnoxService knoxService;
|
||||
|
||||
public KnoxAuthenticationProvider(KnoxService knoxService, NiFiProperties nifiProperties, Authorizer authorizer) {
|
||||
super(nifiProperties, authorizer);
|
||||
this.knoxService = knoxService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
final KnoxAuthenticationRequestToken request = (KnoxAuthenticationRequestToken) authentication;
|
||||
|
||||
try {
|
||||
final String jwtPrincipal = knoxService.getAuthenticationFromToken(request.getToken());
|
||||
final String mappedIdentity = mapIdentity(jwtPrincipal);
|
||||
final NiFiUser user = new Builder().identity(mappedIdentity).groups(getUserGroups(mappedIdentity)).clientAddress(request.getClientAddress()).build();
|
||||
return new NiFiAuthenticationToken(new NiFiUserDetails(user));
|
||||
} catch (ParseException | JOSEException e) {
|
||||
logger.info("Unable to validate the access token: " + e.getMessage(), e);
|
||||
throw new InvalidAuthenticationException("Unable to validate the access token.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> authentication) {
|
||||
return KnoxAuthenticationRequestToken.class.isAssignableFrom(authentication);
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* 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.nifi.web.security.knox;
|
||||
|
||||
import org.apache.nifi.web.security.NiFiAuthenticationRequestToken;
|
||||
|
||||
/**
|
||||
* This is an authentication request with a given JWT token.
|
||||
*/
|
||||
public class KnoxAuthenticationRequestToken extends NiFiAuthenticationRequestToken {
|
||||
|
||||
private final String token;
|
||||
|
||||
/**
|
||||
* Creates a representation of the jwt authentication request for a user.
|
||||
*
|
||||
* @param token The unique token for this user
|
||||
* @param clientAddress the address of the client making the request
|
||||
*/
|
||||
public KnoxAuthenticationRequestToken(final String token, final String clientAddress) {
|
||||
super(clientAddress);
|
||||
setAuthenticated(false);
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<Knox JWT token>";
|
||||
}
|
||||
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* 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.nifi.web.security.knox;
|
||||
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.Set;
|
||||
|
||||
public interface KnoxConfiguration {
|
||||
|
||||
boolean isKnoxEnabled();
|
||||
|
||||
String getKnoxUrl();
|
||||
|
||||
Set<String> getAudiences();
|
||||
|
||||
String getKnoxCookieName();
|
||||
|
||||
RSAPublicKey getKnoxPublicKey();
|
||||
}
|
|
@ -1,244 +0,0 @@
|
|||
/*
|
||||
* 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.nifi.web.security.knox;
|
||||
|
||||
import com.nimbusds.jose.JOSEException;
|
||||
import com.nimbusds.jose.JWSObject;
|
||||
import com.nimbusds.jose.JWSVerifier;
|
||||
import com.nimbusds.jose.crypto.RSASSAVerifier;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.web.security.InvalidAuthenticationException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* KnoxService is a service for managing the Apache Knox SSO.
|
||||
*/
|
||||
public class KnoxService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(KnoxService.class);
|
||||
|
||||
private KnoxConfiguration configuration;
|
||||
private JWSVerifier verifier;
|
||||
private String knoxUrl;
|
||||
private Set<String> audiences;
|
||||
|
||||
/**
|
||||
* Creates a new KnoxService.
|
||||
*
|
||||
* @param configuration knox configuration
|
||||
*/
|
||||
public KnoxService(final KnoxConfiguration configuration) {
|
||||
this.configuration = configuration;
|
||||
|
||||
// if knox sso support is enabled, validate the configuration
|
||||
if (configuration.isKnoxEnabled()) {
|
||||
// ensure the url is provided
|
||||
knoxUrl = configuration.getKnoxUrl();
|
||||
if (StringUtils.isBlank(knoxUrl)) {
|
||||
throw new RuntimeException("Knox URL is required when Apache Knox SSO support is enabled.");
|
||||
}
|
||||
|
||||
// ensure the cookie name is set
|
||||
if (StringUtils.isBlank(configuration.getKnoxCookieName())) {
|
||||
throw new RuntimeException("Knox Cookie Name is required when Apache Knox SSO support is enabled.");
|
||||
}
|
||||
|
||||
// create the verifier
|
||||
verifier = new RSASSAVerifier(configuration.getKnoxPublicKey());
|
||||
|
||||
// get the audience
|
||||
audiences = configuration.getAudiences();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether Knox support is enabled.
|
||||
*
|
||||
* @return whether Knox support is enabled
|
||||
*/
|
||||
public boolean isKnoxEnabled() {
|
||||
return configuration.isKnoxEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Knox Url.
|
||||
*
|
||||
* @return knox url
|
||||
*/
|
||||
public String getKnoxUrl() {
|
||||
if (!configuration.isKnoxEnabled()) {
|
||||
throw new IllegalStateException("Apache Knox SSO is not enabled.");
|
||||
}
|
||||
|
||||
return knoxUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the authentication from the token and verify it.
|
||||
*
|
||||
* @param jwt signed jwt string
|
||||
* @return the user authentication
|
||||
* @throws ParseException if the payload of the jwt doesn't represent a valid json object and a jwt claims set
|
||||
* @throws JOSEException if the JWS object couldn't be verified
|
||||
*/
|
||||
public String getAuthenticationFromToken(final String jwt) throws ParseException, JOSEException {
|
||||
if (!configuration.isKnoxEnabled()) {
|
||||
throw new IllegalStateException("Apache Knox SSO is not enabled.");
|
||||
}
|
||||
|
||||
// attempt to parse the signed jwt
|
||||
final SignedJWT signedJwt = SignedJWT.parse(jwt);
|
||||
|
||||
// validate the token
|
||||
if (validateToken(signedJwt)) {
|
||||
final JWTClaimsSet claimsSet = signedJwt.getJWTClaimsSet();
|
||||
if (claimsSet == null) {
|
||||
logger.info("Claims set is missing from Knox JWT.");
|
||||
throw new InvalidAuthenticationException("The Knox JWT token is not valid.");
|
||||
}
|
||||
|
||||
// extract the user identity from the token
|
||||
return claimsSet.getSubject();
|
||||
} else {
|
||||
throw new InvalidAuthenticationException("The Knox JWT token is not valid.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the specified jwt.
|
||||
*
|
||||
* @param jwtToken knox jwt
|
||||
* @return whether this jwt is valid
|
||||
* @throws JOSEException if the jws object couldn't be verified
|
||||
* @throws ParseException if the payload of the jwt doesn't represent a valid json object and a jwt claims set
|
||||
*/
|
||||
private boolean validateToken(final SignedJWT jwtToken) throws JOSEException, ParseException {
|
||||
final boolean validSignature = validateSignature(jwtToken);
|
||||
final boolean validAudience = validateAudience(jwtToken);
|
||||
final boolean notExpired = validateExpiration(jwtToken);
|
||||
|
||||
return validSignature && validAudience && notExpired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the jwt signature.
|
||||
*
|
||||
* @param jwtToken knox jwt
|
||||
* @return whether this jwt signature is valid
|
||||
* @throws JOSEException if the jws object couldn't be verified
|
||||
*/
|
||||
private boolean validateSignature(final SignedJWT jwtToken) throws JOSEException {
|
||||
boolean valid = false;
|
||||
|
||||
// ensure the token is signed
|
||||
if (JWSObject.State.SIGNED.equals(jwtToken.getState())) {
|
||||
|
||||
// ensure the signature is present
|
||||
if (jwtToken.getSignature() != null) {
|
||||
|
||||
// verify the token
|
||||
valid = jwtToken.verify(verifier);
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
logger.error("The Knox JWT has an invalid signature.");
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the jwt audience.
|
||||
*
|
||||
* @param jwtToken knox jwt
|
||||
* @return whether this jwt audience is valid
|
||||
* @throws ParseException if the payload of the jwt doesn't represent a valid json object and a jwt claims set
|
||||
*/
|
||||
private boolean validateAudience(final SignedJWT jwtToken) throws ParseException {
|
||||
if (audiences == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final JWTClaimsSet claimsSet = jwtToken.getJWTClaimsSet();
|
||||
if (claimsSet == null) {
|
||||
logger.error("Claims set is missing from Knox JWT.");
|
||||
return false;
|
||||
}
|
||||
|
||||
final List<String> tokenAudiences = claimsSet.getAudience();
|
||||
if (tokenAudiences == null) {
|
||||
logger.error("Audience is missing from the Knox JWT.");
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean valid = false;
|
||||
for (final String tokenAudience : tokenAudiences) {
|
||||
// ensure one of the audiences is matched
|
||||
if (audiences.contains(tokenAudience)) {
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
logger.error(String.format("The Knox JWT does not have the required audience(s). Required one of [%s]. Present in JWT [%s].",
|
||||
StringUtils.join(audiences, ", "), StringUtils.join(tokenAudiences, ", ")));
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the jwt expiration.
|
||||
*
|
||||
* @param jwtToken knox jwt
|
||||
* @return whether this jwt is not expired
|
||||
* @throws ParseException if the payload of the jwt doesn't represent a valid json object and a jwt claims set
|
||||
*/
|
||||
private boolean validateExpiration(final SignedJWT jwtToken) throws ParseException {
|
||||
boolean valid = false;
|
||||
|
||||
final JWTClaimsSet claimsSet = jwtToken.getJWTClaimsSet();
|
||||
if (claimsSet == null) {
|
||||
logger.error("Claims set is missing from Knox JWT.");
|
||||
return false;
|
||||
}
|
||||
|
||||
final Date now = new Date();
|
||||
final Date expiration = claimsSet.getExpirationTime();
|
||||
|
||||
// the token is not expired if the expiration isn't present or the expiration is after now
|
||||
if (expiration == null || now.before(expiration)) {
|
||||
valid = true;
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
logger.error("The Knox JWT is expired.");
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* 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.nifi.web.security.knox;
|
||||
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
|
||||
public class KnoxServiceFactoryBean implements FactoryBean<KnoxService> {
|
||||
|
||||
private KnoxService knoxService = null;
|
||||
private NiFiProperties properties = null;
|
||||
|
||||
@Override
|
||||
public KnoxService getObject() {
|
||||
if (knoxService == null) {
|
||||
// ensure we only allow knox if login and oidc are disabled
|
||||
if (properties.isKnoxSsoEnabled() && (properties.isLoginIdentityProviderEnabled() || properties.isOidcEnabled() || properties.isSamlEnabled())) {
|
||||
throw new RuntimeException("Apache Knox SSO support cannot be enabled if the Login Identity Provider or OpenId Connect or SAML is configured.");
|
||||
}
|
||||
|
||||
final KnoxConfiguration configuration = new StandardKnoxConfiguration(properties);
|
||||
knoxService = new KnoxService(configuration);
|
||||
}
|
||||
|
||||
return knoxService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return KnoxService.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setProperties(NiFiProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* 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.nifi.web.security.knox;
|
||||
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.Set;
|
||||
|
||||
public class StandardKnoxConfiguration implements KnoxConfiguration {
|
||||
|
||||
private final NiFiProperties properties;
|
||||
|
||||
public StandardKnoxConfiguration(NiFiProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public boolean isKnoxEnabled() {
|
||||
return properties.isKnoxSsoEnabled();
|
||||
}
|
||||
|
||||
public String getKnoxUrl() {
|
||||
return properties.getKnoxUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAudiences() {
|
||||
return properties.getKnoxAudiences();
|
||||
}
|
||||
|
||||
public String getKnoxCookieName() {
|
||||
return properties.getKnoxCookieName();
|
||||
}
|
||||
|
||||
public RSAPublicKey getKnoxPublicKey() {
|
||||
// get the path to the public key
|
||||
final Path knoxPublicKeyPath = properties.getKnoxPublicKeyPath();
|
||||
|
||||
// ensure the file exists
|
||||
if (Files.isRegularFile(knoxPublicKeyPath) && Files.exists(knoxPublicKeyPath)) {
|
||||
try (final InputStream publicKeyStream = Files.newInputStream(knoxPublicKeyPath)) {
|
||||
final CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
|
||||
final X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(publicKeyStream);
|
||||
return (RSAPublicKey) certificate.getPublicKey();
|
||||
} catch (final IOException | CertificateException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException(String.format("The specified Knox public key path does not exist '%s'", knoxPublicKeyPath.toString()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
/*
|
||||
* 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.nifi.web.security.knox;
|
||||
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import jakarta.servlet.http.Cookie;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class KnoxAuthenticationFilterTest {
|
||||
|
||||
private static final String COOKIE_NAME = "hadoop-jwt";
|
||||
|
||||
private KnoxAuthenticationFilter knoxAuthenticationFilter;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() throws Exception {
|
||||
final NiFiProperties nifiProperties = Mockito.mock(NiFiProperties.class);
|
||||
when(nifiProperties.isKnoxSsoEnabled()).thenReturn(true);
|
||||
when(nifiProperties.getKnoxCookieName()).thenReturn(COOKIE_NAME);
|
||||
|
||||
knoxAuthenticationFilter = new KnoxAuthenticationFilter();
|
||||
knoxAuthenticationFilter.setProperties(nifiProperties);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsecureHttp() {
|
||||
final HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.isSecure()).thenReturn(false);
|
||||
assertNull(knoxAuthenticationFilter.attemptAuthentication(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullCookies() {
|
||||
final HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.isSecure()).thenReturn(true);
|
||||
when(request.getCookies()).thenReturn(null);
|
||||
assertNull(knoxAuthenticationFilter.attemptAuthentication(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoCookies() {
|
||||
final HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.isSecure()).thenReturn(true);
|
||||
when(request.getCookies()).thenReturn(new Cookie[] {});
|
||||
assertNull(knoxAuthenticationFilter.attemptAuthentication(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrongCookieName() {
|
||||
final String jwt = "my-jwt";
|
||||
|
||||
final Cookie knoxCookie = mock(Cookie.class);
|
||||
when(knoxCookie.getName()).thenReturn("not-hadoop-jwt");
|
||||
when(knoxCookie.getValue()).thenReturn(jwt);
|
||||
|
||||
final HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.isSecure()).thenReturn(true);
|
||||
when(request.getCookies()).thenReturn(new Cookie[] {knoxCookie});
|
||||
|
||||
final KnoxAuthenticationRequestToken authRequest = (KnoxAuthenticationRequestToken) knoxAuthenticationFilter.attemptAuthentication(request);
|
||||
assertNull(authRequest);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKnoxCookie() {
|
||||
final String jwt = "my-jwt";
|
||||
|
||||
final Cookie knoxCookie = mock(Cookie.class);
|
||||
when(knoxCookie.getName()).thenReturn(COOKIE_NAME);
|
||||
when(knoxCookie.getValue()).thenReturn(jwt);
|
||||
|
||||
final HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.isSecure()).thenReturn(true);
|
||||
when(request.getCookies()).thenReturn(new Cookie[] {knoxCookie});
|
||||
|
||||
final KnoxAuthenticationRequestToken authRequest = (KnoxAuthenticationRequestToken) knoxAuthenticationFilter.attemptAuthentication(request);
|
||||
assertNotNull(authRequest);
|
||||
assertEquals(jwt, authRequest.getToken());
|
||||
}
|
||||
}
|
|
@ -1,212 +0,0 @@
|
|||
/*
|
||||
* 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.nifi.web.security.knox;
|
||||
|
||||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.PlainJWT;
|
||||
import com.nimbusds.oauth2.sdk.auth.JWTAuthenticationClaimsSet;
|
||||
import com.nimbusds.oauth2.sdk.auth.PrivateKeyJWT;
|
||||
import com.nimbusds.oauth2.sdk.id.Audience;
|
||||
import com.nimbusds.oauth2.sdk.id.ClientID;
|
||||
import com.nimbusds.oauth2.sdk.id.JWTID;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.apache.nifi.web.security.InvalidAuthenticationException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledOnOs;
|
||||
import org.junit.jupiter.api.condition.OS;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@DisabledOnOs({OS.WINDOWS})
|
||||
public class KnoxServiceTest {
|
||||
|
||||
private static final String AUDIENCE = "https://apache-knox/token";
|
||||
private static final String AUDIENCE_2 = "https://apache-knox-2/token";
|
||||
|
||||
@Test
|
||||
public void testKnoxSsoNotEnabledGetKnoxUrl() {
|
||||
final KnoxConfiguration configuration = mock(KnoxConfiguration.class);
|
||||
when(configuration.isKnoxEnabled()).thenReturn(false);
|
||||
|
||||
final KnoxService service = new KnoxService(configuration);
|
||||
assertFalse(service.isKnoxEnabled());
|
||||
|
||||
assertThrows(IllegalStateException.class, service::getKnoxUrl);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKnoxSsoNotEnabledGetAuthenticatedFromToken() {
|
||||
final KnoxConfiguration configuration = mock(KnoxConfiguration.class);
|
||||
when(configuration.isKnoxEnabled()).thenReturn(false);
|
||||
|
||||
final KnoxService service = new KnoxService(configuration);
|
||||
assertFalse(service.isKnoxEnabled());
|
||||
|
||||
assertThrows(IllegalStateException.class, () -> service.getAuthenticationFromToken("jwt-token-value"));
|
||||
}
|
||||
|
||||
private JWTAuthenticationClaimsSet getAuthenticationClaimsSet(final String subject, final String audience, final Date expiration) {
|
||||
return new JWTAuthenticationClaimsSet(
|
||||
new ClientID(subject),
|
||||
new Audience(audience).toSingleAudienceList(),
|
||||
expiration,
|
||||
null,
|
||||
null,
|
||||
new JWTID());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSignedJwt() throws Exception {
|
||||
final String subject = "user-1";
|
||||
final Date expiration = new Date(System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(5, TimeUnit.SECONDS));
|
||||
|
||||
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
|
||||
final KeyPair pair = keyGen.generateKeyPair();
|
||||
final RSAPublicKey publicKey = (RSAPublicKey) pair.getPublic();
|
||||
|
||||
final JWTAuthenticationClaimsSet claimsSet = getAuthenticationClaimsSet(subject, AUDIENCE, expiration);
|
||||
final PrivateKeyJWT privateKeyJWT = new PrivateKeyJWT(claimsSet, JWSAlgorithm.RS256, pair.getPrivate(), null, null);
|
||||
|
||||
final KnoxConfiguration configuration = getConfiguration(publicKey);
|
||||
final KnoxService service = new KnoxService(configuration);
|
||||
|
||||
assertEquals(subject, service.getAuthenticationFromToken(privateKeyJWT.getClientAssertion().serialize()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadSignedJwt() throws Exception {
|
||||
final String subject = "user-1";
|
||||
final Date expiration = new Date(System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(5, TimeUnit.SECONDS));
|
||||
|
||||
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
|
||||
|
||||
final KeyPair pair1 = keyGen.generateKeyPair();
|
||||
final KeyPair pair2 = keyGen.generateKeyPair();
|
||||
final RSAPublicKey publicKey2 = (RSAPublicKey) pair2.getPublic();
|
||||
|
||||
// sign the jwt with pair 1
|
||||
final JWTAuthenticationClaimsSet claimsSet = getAuthenticationClaimsSet(subject, AUDIENCE, expiration);
|
||||
final PrivateKeyJWT privateKeyJWT = new PrivateKeyJWT(claimsSet, JWSAlgorithm.RS256, pair1.getPrivate(), null, null);
|
||||
|
||||
// attempt to verify it with pair 2
|
||||
final KnoxConfiguration configuration = getConfiguration(publicKey2);
|
||||
final KnoxService service = new KnoxService(configuration);
|
||||
|
||||
assertThrows(InvalidAuthenticationException.class, () -> service.getAuthenticationFromToken(privateKeyJWT.getClientAssertion().serialize()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlainJwt() throws Exception {
|
||||
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
|
||||
final KeyPair pair = keyGen.generateKeyPair();
|
||||
final RSAPublicKey publicKey = (RSAPublicKey) pair.getPublic();
|
||||
|
||||
final Date expiration = new Date(System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(5, TimeUnit.SECONDS));
|
||||
final JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
|
||||
.subject("user-1")
|
||||
.expirationTime(expiration)
|
||||
.build();
|
||||
|
||||
final PlainJWT plainJWT = new PlainJWT(claimsSet);
|
||||
|
||||
final KnoxConfiguration configuration = getConfiguration(publicKey);
|
||||
final KnoxService service = new KnoxService(configuration);
|
||||
|
||||
assertThrows(ParseException.class, () -> service.getAuthenticationFromToken(plainJWT.serialize()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpiredJwt() throws Exception {
|
||||
final String subject = "user-1";
|
||||
|
||||
// token expires in 1 sec
|
||||
final Date expiration = new Date(System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS));
|
||||
|
||||
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
|
||||
final KeyPair pair = keyGen.generateKeyPair();
|
||||
final RSAPublicKey publicKey = (RSAPublicKey) pair.getPublic();
|
||||
|
||||
// wait 2 sec
|
||||
Thread.sleep(TimeUnit.MILLISECONDS.convert(2, TimeUnit.SECONDS));
|
||||
|
||||
final JWTAuthenticationClaimsSet claimsSet = getAuthenticationClaimsSet(subject, AUDIENCE, expiration);
|
||||
final PrivateKeyJWT privateKeyJWT = new PrivateKeyJWT(claimsSet, JWSAlgorithm.RS256, pair.getPrivate(), null, null);
|
||||
|
||||
final KnoxConfiguration configuration = getConfiguration(publicKey);
|
||||
final KnoxService service = new KnoxService(configuration);
|
||||
|
||||
assertThrows(InvalidAuthenticationException.class, () -> service.getAuthenticationFromToken(privateKeyJWT.getClientAssertion().serialize()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiredAudience() throws Exception {
|
||||
final String subject = "user-1";
|
||||
final Date expiration = new Date(System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(5, TimeUnit.SECONDS));
|
||||
|
||||
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
|
||||
final KeyPair pair = keyGen.generateKeyPair();
|
||||
final RSAPublicKey publicKey = (RSAPublicKey) pair.getPublic();
|
||||
|
||||
final JWTAuthenticationClaimsSet claimsSet = getAuthenticationClaimsSet(subject, AUDIENCE, expiration);
|
||||
final PrivateKeyJWT privateKeyJWT = new PrivateKeyJWT(claimsSet, JWSAlgorithm.RS256, pair.getPrivate(), null, null);
|
||||
|
||||
final KnoxConfiguration configuration = getConfiguration(publicKey);
|
||||
when(configuration.getAudiences()).thenReturn(null);
|
||||
final KnoxService service = new KnoxService(configuration);
|
||||
|
||||
assertEquals(subject, service.getAuthenticationFromToken(privateKeyJWT.getClientAssertion().serialize()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidAudience() throws Exception {
|
||||
final String subject = "user-1";
|
||||
final Date expiration = new Date(System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(5, TimeUnit.SECONDS));
|
||||
|
||||
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
|
||||
final KeyPair pair = keyGen.generateKeyPair();
|
||||
final RSAPublicKey publicKey = (RSAPublicKey) pair.getPublic();
|
||||
|
||||
final JWTAuthenticationClaimsSet claimsSet = getAuthenticationClaimsSet(subject, "incorrect-audience", expiration);
|
||||
final PrivateKeyJWT privateKeyJWT = new PrivateKeyJWT(claimsSet, JWSAlgorithm.RS256, pair.getPrivate(), null, null);
|
||||
|
||||
final KnoxConfiguration configuration = getConfiguration(publicKey);
|
||||
final KnoxService service = new KnoxService(configuration);
|
||||
assertThrows(InvalidAuthenticationException.class, () -> service.getAuthenticationFromToken(privateKeyJWT.getClientAssertion().serialize()));
|
||||
}
|
||||
|
||||
private KnoxConfiguration getConfiguration(final RSAPublicKey publicKey) {
|
||||
final KnoxConfiguration configuration = mock(KnoxConfiguration.class);
|
||||
when(configuration.isKnoxEnabled()).thenReturn(true);
|
||||
when(configuration.getKnoxUrl()).thenReturn("knox-sso-url");
|
||||
when(configuration.getKnoxCookieName()).thenReturn("knox-cookie-name");
|
||||
when(configuration.getAudiences()).thenReturn(Stream.of(AUDIENCE, AUDIENCE_2).collect(Collectors.toSet()));
|
||||
when(configuration.getKnoxPublicKey()).thenReturn(publicKey);
|
||||
return configuration;
|
||||
}
|
||||
}
|
|
@ -38,8 +38,6 @@ public class LoginFilter implements Filter {
|
|||
|
||||
private static final String SAML2_AUTHENTICATE_FILTER_PATH = "/nifi-api/saml2/authenticate/consumer";
|
||||
|
||||
private static final String KNOX_REQUEST_PATH = "/nifi-api/access/knox/request";
|
||||
|
||||
private ServletContext servletContext;
|
||||
|
||||
@Override
|
||||
|
@ -50,16 +48,12 @@ public class LoginFilter implements Filter {
|
|||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
|
||||
final boolean supportsOidc = Boolean.parseBoolean(servletContext.getInitParameter("oidc-supported"));
|
||||
final boolean supportsKnoxSso = Boolean.parseBoolean(servletContext.getInitParameter("knox-supported"));
|
||||
final boolean supportsSAML = Boolean.parseBoolean(servletContext.getInitParameter("saml-supported"));
|
||||
|
||||
final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
|
||||
final RequestUriBuilder requestUriBuilder = RequestUriBuilder.fromHttpServletRequest(httpServletRequest);
|
||||
|
||||
if (supportsKnoxSso) {
|
||||
final URI redirectUri = requestUriBuilder.path(KNOX_REQUEST_PATH).build();
|
||||
sendRedirect(response, redirectUri);
|
||||
} else if (supportsOidc) {
|
||||
if (supportsOidc) {
|
||||
final URI redirectUri = requestUriBuilder.path(OAUTH2_AUTHORIZATION_PATH).build();
|
||||
// Redirect to authorization URL defined in Spring Security OAuth2AuthorizationRequestRedirectFilter
|
||||
sendRedirect(response, redirectUri);
|
||||
|
|
|
@ -41,8 +41,6 @@ public class LogoutFilter implements Filter {
|
|||
|
||||
private static final String SAML_SINGLE_LOGOUT_URL = "/nifi-api/access/saml/single-logout/request";
|
||||
|
||||
private static final String KNOX_LOGOUT_URL = "/nifi-api/access/knox/logout";
|
||||
|
||||
private static final String LOGOUT_COMPLETE_URL = "/nifi-api/access/logout/complete";
|
||||
|
||||
private ServletContext servletContext;
|
||||
|
@ -55,7 +53,6 @@ public class LogoutFilter implements Filter {
|
|||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException {
|
||||
final boolean supportsOidc = Boolean.parseBoolean(servletContext.getInitParameter("oidc-supported"));
|
||||
final boolean supportsKnoxSso = Boolean.parseBoolean(servletContext.getInitParameter("knox-supported"));
|
||||
final boolean supportsSaml = Boolean.parseBoolean(servletContext.getInitParameter("saml-supported"));
|
||||
final boolean supportsSamlSingleLogout = Boolean.parseBoolean(servletContext.getInitParameter("saml-single-logout-supported"));
|
||||
|
||||
|
@ -68,8 +65,6 @@ public class LogoutFilter implements Filter {
|
|||
|
||||
if (supportsOidc) {
|
||||
sendRedirect(OIDC_LOGOUT_URL, request, response);
|
||||
} else if (supportsKnoxSso) {
|
||||
sendRedirect(KNOX_LOGOUT_URL, request, response);
|
||||
} else if (supportsSaml) {
|
||||
final String logoutUrl = supportsSamlSingleLogout ? SAML_SINGLE_LOGOUT_URL : SAML_LOCAL_LOGOUT_URL;
|
||||
sendRedirect(logoutUrl, request, response);
|
||||
|
|
|
@ -175,12 +175,6 @@ nifi.security.user.oidc.client.id=
|
|||
nifi.security.user.oidc.client.secret=
|
||||
nifi.security.user.oidc.preferred.jwsalgorithm=
|
||||
|
||||
# Apache Knox SSO Properties #
|
||||
nifi.security.user.knox.url=
|
||||
nifi.security.user.knox.publicKey=
|
||||
nifi.security.user.knox.cookieName=hadoop-jwt
|
||||
nifi.security.user.knox.audiences=
|
||||
|
||||
# Identity Mapping Properties #
|
||||
# These properties allow normalizing user identities such that identities coming from different identity providers
|
||||
# (certificates, LDAP, Kerberos) can be treated the same internally in NiFi. The following example demonstrates normalizing
|
||||
|
|
|
@ -175,12 +175,6 @@ nifi.security.user.oidc.client.id=
|
|||
nifi.security.user.oidc.client.secret=
|
||||
nifi.security.user.oidc.preferred.jwsalgorithm=
|
||||
|
||||
# Apache Knox SSO Properties #
|
||||
nifi.security.user.knox.url=
|
||||
nifi.security.user.knox.publicKey=
|
||||
nifi.security.user.knox.cookieName=hadoop-jwt
|
||||
nifi.security.user.knox.audiences=
|
||||
|
||||
# Identity Mapping Properties #
|
||||
# These properties allow normalizing user identities such that identities coming from different identity providers
|
||||
# (certificates, LDAP, Kerberos) can be treated the same internally in NiFi. The following example demonstrates normalizing
|
||||
|
|
|
@ -176,12 +176,6 @@ nifi.security.user.oidc.client.id=
|
|||
nifi.security.user.oidc.client.secret=
|
||||
nifi.security.user.oidc.preferred.jwsalgorithm=
|
||||
|
||||
# Apache Knox SSO Properties #
|
||||
nifi.security.user.knox.url=
|
||||
nifi.security.user.knox.publicKey=
|
||||
nifi.security.user.knox.cookieName=hadoop-jwt
|
||||
nifi.security.user.knox.audiences=
|
||||
|
||||
# Identity Mapping Properties #
|
||||
# These properties allow normalizing user identities such that identities coming from different identity providers
|
||||
# (certificates, LDAP, Kerberos) can be treated the same internally in NiFi. The following example demonstrates normalizing
|
||||
|
|
|
@ -180,12 +180,6 @@ nifi.security.user.oidc.client.id=
|
|||
nifi.security.user.oidc.client.secret=
|
||||
nifi.security.user.oidc.preferred.jwsalgorithm=
|
||||
|
||||
# Apache Knox SSO Properties #
|
||||
nifi.security.user.knox.url=
|
||||
nifi.security.user.knox.publicKey=
|
||||
nifi.security.user.knox.cookieName=hadoop-jwt
|
||||
nifi.security.user.knox.audiences=
|
||||
|
||||
# Identity Mapping Properties #
|
||||
# These properties allow normalizing user identities such that identities coming from different identity providers
|
||||
# (certificates, LDAP, Kerberos) can be treated the same internally in NiFi. The following example demonstrates normalizing
|
||||
|
|
Loading…
Reference in New Issue