mirror of https://github.com/apache/nifi.git
NIFI-655:
- Creating an endpoint for returning the identity of the current user. - Updating the LoginAuthenticationFilter.
This commit is contained in:
parent
a40e5a07ba
commit
e7a5e18221
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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.api.dto;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
* Details for the login configuration.
|
||||
*/
|
||||
@XmlType(name = "loginConfig")
|
||||
public class LoginConfigurationDTO {
|
||||
|
||||
private Boolean supportsLogin;
|
||||
private Boolean supportsRegistration;
|
||||
|
||||
/**
|
||||
* @return Indicates whether or not this NiFi supports user login.
|
||||
*/
|
||||
@ApiModelProperty(
|
||||
value = "Indicates whether or not this NiFi supports user login.",
|
||||
readOnly = true
|
||||
)
|
||||
public Boolean getSupportsLogin() {
|
||||
return supportsLogin;
|
||||
}
|
||||
|
||||
public void setSupportsLogin(Boolean supportsLogin) {
|
||||
this.supportsLogin = supportsLogin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return If this NiFi supports login, indicates whether or not registration is supported.
|
||||
*/
|
||||
@ApiModelProperty(
|
||||
value = "If this NiFi supports login, indicates whether or not registration is supported.",
|
||||
readOnly = true
|
||||
)
|
||||
public Boolean getSupportsRegistration() {
|
||||
return supportsRegistration;
|
||||
}
|
||||
|
||||
public void setSupportsRegistration(Boolean supportsRegistration) {
|
||||
this.supportsRegistration = supportsRegistration;
|
||||
}
|
||||
}
|
|
@ -14,24 +14,30 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.nifi.web.security.token;
|
||||
package org.apache.nifi.web.api.entity;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.nifi.authentication.LoginCredentials;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import org.apache.nifi.web.api.dto.LoginConfigurationDTO;
|
||||
|
||||
/**
|
||||
* This is an Authentication Token for requesting an ID token for accessing the NIFI REST API.
|
||||
* A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a LoginConfigurationDTO.
|
||||
*/
|
||||
public class LoginAuthenticationRequestToken extends NiFiAuthenticationRequestToken {
|
||||
@XmlRootElement(name = "loginConfigurationEntity")
|
||||
public class LoginConfigurationEntity extends Entity {
|
||||
|
||||
final LoginCredentials credentials;
|
||||
private LoginConfigurationDTO config;
|
||||
|
||||
public LoginAuthenticationRequestToken(final List<String> proxyChain, final LoginCredentials credentials) {
|
||||
super(proxyChain);
|
||||
this.credentials = credentials;
|
||||
/**
|
||||
* The LoginConfigurationDTO that is being serialized.
|
||||
*
|
||||
* @return The LoginConfigurationDTO object
|
||||
*/
|
||||
public LoginConfigurationDTO getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public LoginCredentials getLoginCredentials() {
|
||||
return credentials;
|
||||
public void setConfig(LoginConfigurationDTO config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
}
|
|
@ -43,6 +43,7 @@ import org.apache.nifi.web.api.dto.ProcessGroupDTO;
|
|||
import org.apache.nifi.web.api.dto.ProcessorDTO;
|
||||
import org.apache.nifi.web.api.dto.ComponentHistoryDTO;
|
||||
import org.apache.nifi.web.api.dto.ControllerServiceReferencingComponentDTO;
|
||||
import org.apache.nifi.web.api.dto.LoginConfigurationDTO;
|
||||
import org.apache.nifi.web.api.dto.PropertyDescriptorDTO;
|
||||
import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO;
|
||||
import org.apache.nifi.web.api.dto.RemoteProcessGroupPortDTO;
|
||||
|
@ -177,6 +178,13 @@ public interface NiFiServiceFacade {
|
|||
*/
|
||||
ControllerConfigurationDTO getControllerConfiguration();
|
||||
|
||||
/**
|
||||
* Gets the login configuration for this controller.
|
||||
*
|
||||
* @return The login configuration
|
||||
*/
|
||||
LoginConfigurationDTO getLoginConfiguration();
|
||||
|
||||
/**
|
||||
* Updates the configuration for this controller.
|
||||
*
|
||||
|
|
|
@ -24,7 +24,6 @@ import org.apache.nifi.web.security.NiFiAuthenticationProvider;
|
|||
import org.apache.nifi.web.security.anonymous.NiFiAnonymousUserFilter;
|
||||
import org.apache.nifi.web.security.NiFiAuthenticationEntryPoint;
|
||||
import org.apache.nifi.web.security.form.LoginAuthenticationFilter;
|
||||
import org.apache.nifi.web.security.form.LoginAuthenticationProvider;
|
||||
import org.apache.nifi.web.security.jwt.JwtAuthenticationFilter;
|
||||
import org.apache.nifi.web.security.jwt.JwtAuthenticationProvider;
|
||||
import org.apache.nifi.web.security.jwt.JwtService;
|
||||
|
@ -37,6 +36,7 @@ import org.apache.nifi.web.security.x509.ocsp.OcspCertificateValidator;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
|
@ -75,6 +75,7 @@ public class NiFiWebApiSecurityConfiguration extends WebSecurityConfigurerAdapte
|
|||
.authenticationEntryPoint(new NiFiAuthenticationEntryPoint())
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.antMatchers(HttpMethod.GET, "/controller/login/config").permitAll()
|
||||
.anyRequest().fullyAuthenticated()
|
||||
.and()
|
||||
.sessionManagement()
|
||||
|
@ -113,15 +114,10 @@ public class NiFiWebApiSecurityConfiguration extends WebSecurityConfigurerAdapte
|
|||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
final LoginAuthenticationProvider baseLoginAuthenticationProvider = new LoginAuthenticationProvider();
|
||||
baseLoginAuthenticationProvider.setLoginIdentityProvider(loginIdentityProvider);
|
||||
|
||||
final AuthenticationProvider loginAuthenticationProvider = new NiFiAuthenticationProvider(baseLoginAuthenticationProvider, userDetailsService);
|
||||
final AuthenticationProvider x509AuthenticationProvider = new NiFiAuthenticationProvider(new X509AuthenticationProvider(), userDetailsService);
|
||||
final AuthenticationProvider jwtAuthenticationProvider = new NiFiAuthenticationProvider(new JwtAuthenticationProvider(), userDetailsService);
|
||||
|
||||
auth
|
||||
.authenticationProvider(loginAuthenticationProvider)
|
||||
.authenticationProvider(x509AuthenticationProvider)
|
||||
.authenticationProvider(jwtAuthenticationProvider);
|
||||
}
|
||||
|
@ -129,7 +125,7 @@ public class NiFiWebApiSecurityConfiguration extends WebSecurityConfigurerAdapte
|
|||
private LoginAuthenticationFilter buildLoginFilter(final String url) {
|
||||
final LoginAuthenticationFilter loginFilter = new LoginAuthenticationFilter(url);
|
||||
loginFilter.setJwtService(jwtService);
|
||||
loginFilter.setLoginIdentityProvider(loginIdentityProvider);
|
||||
loginFilter.setUserDetailsService(userDetailsService);
|
||||
loginFilter.setPrincipalExtractor(new SubjectDnX509PrincipalExtractor());
|
||||
loginFilter.setCertificateExtractor(new X509CertificateExtractor());
|
||||
return loginFilter;
|
||||
|
|
|
@ -153,6 +153,7 @@ import org.apache.nifi.web.util.SnippetUtils;
|
|||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.authentication.LoginIdentityProvider;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.Validator;
|
||||
import org.apache.nifi.controller.ReportingTaskNode;
|
||||
|
@ -163,6 +164,7 @@ import org.apache.nifi.controller.service.ControllerServiceState;
|
|||
import org.apache.nifi.reporting.ComponentType;
|
||||
import org.apache.nifi.web.api.dto.ControllerServiceDTO;
|
||||
import org.apache.nifi.web.api.dto.ControllerServiceReferencingComponentDTO;
|
||||
import org.apache.nifi.web.api.dto.LoginConfigurationDTO;
|
||||
import org.apache.nifi.web.api.dto.PropertyDescriptorDTO;
|
||||
import org.apache.nifi.web.api.dto.ReportingTaskDTO;
|
||||
import org.apache.nifi.web.api.dto.status.ClusterProcessGroupStatusDTO;
|
||||
|
@ -205,6 +207,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
|||
// administrative services
|
||||
private AuditService auditService;
|
||||
private UserService userService;
|
||||
private LoginIdentityProvider loginIdentityProvider;
|
||||
|
||||
// cluster manager
|
||||
private WebClusterManager clusterManager;
|
||||
|
@ -2347,6 +2350,22 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
|||
return controllerFacade.getInstanceId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoginConfigurationDTO getLoginConfiguration() {
|
||||
final LoginConfigurationDTO loginConfiguration = new LoginConfigurationDTO();
|
||||
|
||||
// specify whether login/registration should be supported
|
||||
if (loginIdentityProvider == null) {
|
||||
loginConfiguration.setSupportsLogin(false);
|
||||
loginConfiguration.setSupportsRegistration(false);
|
||||
} else {
|
||||
loginConfiguration.setSupportsLogin(true);
|
||||
loginConfiguration.setSupportsRegistration(loginIdentityProvider.supportsRegistration());
|
||||
}
|
||||
|
||||
return loginConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ControllerConfigurationDTO getControllerConfiguration() {
|
||||
ControllerConfigurationDTO controllerConfig = new ControllerConfigurationDTO();
|
||||
|
@ -3407,6 +3426,10 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
|||
this.snippetUtils = snippetUtils;
|
||||
}
|
||||
|
||||
public void setLoginIdentityProvider(LoginIdentityProvider loginIdentityProvider) {
|
||||
this.loginIdentityProvider = loginIdentityProvider;
|
||||
}
|
||||
|
||||
private boolean isPrimaryNode(String nodeId) {
|
||||
final Node primaryNode = clusterManager.getPrimaryNode();
|
||||
return (primaryNode != null && primaryNode.getNodeId().getId().equals(nodeId));
|
||||
|
|
|
@ -78,8 +78,10 @@ import org.apache.nifi.web.api.request.ClientIdParameter;
|
|||
import org.apache.nifi.web.api.request.IntegerParameter;
|
||||
import org.apache.nifi.web.api.request.LongParameter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.web.api.dto.LoginConfigurationDTO;
|
||||
import org.apache.nifi.web.api.entity.ControllerServiceTypesEntity;
|
||||
import org.apache.nifi.web.api.entity.IdentityEntity;
|
||||
import org.apache.nifi.web.api.entity.LoginConfigurationEntity;
|
||||
import org.apache.nifi.web.api.entity.ReportingTaskTypesEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
|
||||
|
@ -654,6 +656,53 @@ public class ControllerResource extends ApplicationResource {
|
|||
return clusterContext(generateOkResponse(entity)).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the login configuration for this NiFi.
|
||||
*
|
||||
* @param httpServletRequest the servlet request
|
||||
* @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
|
||||
* @return A loginConfigurationEntity
|
||||
*/
|
||||
@GET
|
||||
@Consumes(MediaType.WILDCARD)
|
||||
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
|
||||
@Path("/login/config")
|
||||
@ApiOperation(
|
||||
value = "Retrieves the login configuration for this NiFi",
|
||||
response = LoginConfigurationEntity.class
|
||||
)
|
||||
public Response getLoginConfig(
|
||||
@Context HttpServletRequest httpServletRequest,
|
||||
@ApiParam(
|
||||
value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
|
||||
required = false
|
||||
)
|
||||
@QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId) {
|
||||
|
||||
// replicate if cluster manager
|
||||
if (properties.isClusterManager()) {
|
||||
return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
|
||||
}
|
||||
|
||||
final LoginConfigurationDTO loginConfig = serviceFacade.getLoginConfiguration();
|
||||
|
||||
// only support login/registration when running securely
|
||||
loginConfig.setSupportsLogin(loginConfig.getSupportsLogin() && httpServletRequest.isSecure());
|
||||
loginConfig.setSupportsRegistration(loginConfig.getSupportsRegistration() && httpServletRequest.isSecure());
|
||||
|
||||
// create the revision
|
||||
final RevisionDTO revision = new RevisionDTO();
|
||||
revision.setClientId(clientId.getClientId());
|
||||
|
||||
// create the response entity
|
||||
final LoginConfigurationEntity entity = new LoginConfigurationEntity();
|
||||
entity.setRevision(revision);
|
||||
entity.setConfig(loginConfig);
|
||||
|
||||
// generate the response
|
||||
return clusterContext(generateOkResponse(entity)).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the configuration for this NiFi.
|
||||
*
|
||||
|
|
|
@ -122,6 +122,7 @@
|
|||
<property name="optimisticLockingManager" ref="webOptimisticLockingManager"/>
|
||||
<property name="dtoFactory" ref="dtoFactory"/>
|
||||
<property name="clusterManager" ref="clusterManager"/>
|
||||
<property name="loginIdentityProvider" ref="loginIdentityProvider"/>
|
||||
</bean>
|
||||
|
||||
<!-- depecrated -->
|
||||
|
|
|
@ -26,16 +26,21 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.apache.nifi.authentication.LoginCredentials;
|
||||
import org.apache.nifi.authentication.LoginIdentityProvider;
|
||||
import org.apache.nifi.util.StringUtils;
|
||||
import org.apache.nifi.web.security.ProxiedEntitiesUtils;
|
||||
import org.apache.nifi.web.security.jwt.JwtService;
|
||||
import org.apache.nifi.web.security.token.NiFiAuthenticationRequestToken;
|
||||
import org.apache.nifi.web.security.token.LoginAuthenticationRequestToken;
|
||||
import org.apache.nifi.web.security.x509.X509CertificateExtractor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException;
|
||||
import org.springframework.security.web.authentication.preauth.x509.X509PrincipalExtractor;
|
||||
|
||||
/**
|
||||
|
@ -45,11 +50,13 @@ public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingF
|
|||
|
||||
private static final Logger logger = LoggerFactory.getLogger(LoginAuthenticationFilter.class);
|
||||
|
||||
private AuthenticationUserDetailsService<NiFiAuthenticationRequestToken> userDetailsService;
|
||||
|
||||
private X509CertificateExtractor certificateExtractor;
|
||||
private X509PrincipalExtractor principalExtractor;
|
||||
|
||||
private JwtService jwtService;
|
||||
private LoginIdentityProvider loginIdentityProvider;
|
||||
private JwtService jwtService;
|
||||
|
||||
public LoginAuthenticationFilter(final String defaultFilterProcessesUrl) {
|
||||
super(defaultFilterProcessesUrl);
|
||||
|
@ -65,33 +72,69 @@ public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingF
|
|||
return null;
|
||||
}
|
||||
|
||||
// look for a certificate
|
||||
final X509Certificate certificate = certificateExtractor.extractClientCertificate(request);
|
||||
// look for the credentials in the request
|
||||
final LoginCredentials credentials = getLoginCredentials(request);
|
||||
|
||||
// ensure the cert was found
|
||||
if (certificate != null) {
|
||||
// extract the principal
|
||||
Object certificatePrincipal = principalExtractor.extractPrincipal(certificate);
|
||||
final String principal = ProxiedEntitiesUtils.formatProxyDn(certificatePrincipal.toString());
|
||||
// if the credentials were not part of the request, attempt to log in with the certificate in the request
|
||||
if (credentials == null) {
|
||||
// look for a certificate
|
||||
final X509Certificate certificate = certificateExtractor.extractClientCertificate(request);
|
||||
|
||||
final List<String> proxyChain = ProxiedEntitiesUtils.buildProxyChain(request, principal);
|
||||
return new NiFiAuthenticationRequestToken(proxyChain);
|
||||
} else {
|
||||
// if there were no certificate or no principal, defer to the login provider
|
||||
final LoginCredentials credentials = getLoginCredentials(request);
|
||||
|
||||
// if unable to authenticate return null
|
||||
if (credentials == null) {
|
||||
return null;
|
||||
if (certificate == null) {
|
||||
throw new PreAuthenticatedCredentialsNotFoundException("Unable to extract client certificate after processing request with no login credentials specified.");
|
||||
}
|
||||
|
||||
final List<String> proxyChain = ProxiedEntitiesUtils.buildProxyChain(request, credentials.getUsername());
|
||||
return new LoginAuthenticationRequestToken(proxyChain, credentials);
|
||||
// authorize the proxy if necessary
|
||||
final String principal = extractPrincipal(certificate);
|
||||
authorizeProxyIfNecessary(ProxiedEntitiesUtils.buildProxyChain(request, principal));
|
||||
|
||||
final LoginCredentials preAuthenticatedCredentials = new LoginCredentials(principal, null);
|
||||
return new LoginAuthenticationToken(preAuthenticatedCredentials);
|
||||
} else {
|
||||
// look for a certificate
|
||||
final X509Certificate certificate = certificateExtractor.extractClientCertificate(request);
|
||||
|
||||
// if there was a certificate with this request see if it was proxying an end user request
|
||||
if (certificate != null) {
|
||||
// authorize the proxy if necessary
|
||||
final String principal = extractPrincipal(certificate);
|
||||
authorizeProxyIfNecessary(ProxiedEntitiesUtils.buildProxyChain(request, principal));
|
||||
}
|
||||
|
||||
if (loginIdentityProvider.authenticate(credentials)) {
|
||||
return new LoginAuthenticationToken(credentials);
|
||||
} else {
|
||||
throw new BadCredentialsException("User could not be authenticated with the configured identity provider.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void authorizeProxyIfNecessary(final List<String> proxyChain) throws AuthenticationException {
|
||||
if (proxyChain.size() > 1) {
|
||||
try {
|
||||
userDetailsService.loadUserDetails(new NiFiAuthenticationRequestToken(proxyChain));
|
||||
} catch (final UsernameNotFoundException unfe) {
|
||||
// if a username not found exception was thrown, the proxies were authorized and now
|
||||
// we can issue a new ID token to the end user
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String extractPrincipal(final X509Certificate certificate) {
|
||||
// extract the principal
|
||||
final Object certificatePrincipal = principalExtractor.extractPrincipal(certificate);
|
||||
return ProxiedEntitiesUtils.formatProxyDn(certificatePrincipal.toString());
|
||||
}
|
||||
|
||||
private LoginCredentials getLoginCredentials(HttpServletRequest request) {
|
||||
return new LoginCredentials(request.getParameter("username"), request.getParameter("password"));
|
||||
final String username = request.getParameter("username");
|
||||
final String password = request.getParameter("password");
|
||||
|
||||
if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
|
||||
return null;
|
||||
} else {
|
||||
return new LoginCredentials(username, password);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -112,6 +155,34 @@ public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingF
|
|||
out.println("Invalid username/password");
|
||||
}
|
||||
|
||||
/**
|
||||
* This is an Authentication Token for logging in. Once a user is authenticated, they can be issues an ID token.
|
||||
*/
|
||||
public static class LoginAuthenticationToken extends AbstractAuthenticationToken {
|
||||
|
||||
final LoginCredentials credentials;
|
||||
|
||||
public LoginAuthenticationToken(final LoginCredentials credentials) {
|
||||
super(null);
|
||||
setAuthenticated(true);
|
||||
this.credentials = credentials;
|
||||
}
|
||||
|
||||
public LoginCredentials getLoginCredentials() {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
return credentials.getPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return credentials.getUsername();
|
||||
}
|
||||
}
|
||||
|
||||
public void setJwtService(JwtService jwtService) {
|
||||
this.jwtService = jwtService;
|
||||
}
|
||||
|
@ -128,4 +199,8 @@ public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingF
|
|||
this.principalExtractor = principalExtractor;
|
||||
}
|
||||
|
||||
public void setUserDetailsService(AuthenticationUserDetailsService<NiFiAuthenticationRequestToken> userDetailsService) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,53 +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.form;
|
||||
|
||||
import org.apache.nifi.authentication.LoginIdentityProvider;
|
||||
import org.apache.nifi.web.security.token.LoginAuthenticationRequestToken;
|
||||
import org.apache.nifi.web.security.token.LoginAuthenticationToken;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class LoginAuthenticationProvider implements AuthenticationProvider {
|
||||
|
||||
private LoginIdentityProvider loginIdentityProvider;
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
final LoginAuthenticationRequestToken loginAuthenticationToken = (LoginAuthenticationRequestToken) authentication;
|
||||
|
||||
if (loginIdentityProvider.authenticate(loginAuthenticationToken.getLoginCredentials())) {
|
||||
return new LoginAuthenticationToken(loginAuthenticationToken.getLoginCredentials());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> authentication) {
|
||||
return LoginAuthenticationRequestToken.class.isAssignableFrom(authentication);
|
||||
}
|
||||
|
||||
public void setLoginIdentityProvider(LoginIdentityProvider loginIdentityProvider) {
|
||||
this.loginIdentityProvider = loginIdentityProvider;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,48 +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.token;
|
||||
|
||||
import org.apache.nifi.authentication.LoginCredentials;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
|
||||
/**
|
||||
* This is an Authentication Token for logging in. Once a user is authenticated, they can be issues an ID token.
|
||||
*/
|
||||
public class LoginAuthenticationToken extends AbstractAuthenticationToken {
|
||||
|
||||
final LoginCredentials credentials;
|
||||
|
||||
public LoginAuthenticationToken(final LoginCredentials credentials) {
|
||||
super(null);
|
||||
setAuthenticated(true);
|
||||
this.credentials = credentials;
|
||||
}
|
||||
|
||||
public LoginCredentials getLoginCredentials() {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
return credentials.getPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return credentials.getUsername();
|
||||
}
|
||||
}
|
|
@ -16,16 +16,12 @@
|
|||
*/
|
||||
package org.apache.nifi.web;
|
||||
|
||||
import org.apache.nifi.web.security.form.LoginAuthenticationFilter;
|
||||
import org.apache.nifi.web.security.jwt.JwtService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
/**
|
||||
* NiFi Web Ui Security Config
|
||||
|
@ -38,32 +34,11 @@ public class NiFiWebUiSecurityConfiguration extends WebSecurityConfigurerAdapter
|
|||
super(true); // disable defaults
|
||||
}
|
||||
|
||||
private JwtService jwtService;
|
||||
|
||||
@Override
|
||||
protected void configure(final HttpSecurity http) throws Exception {
|
||||
http
|
||||
.addFilterBefore(buildFormLoginFilter(), UsernamePasswordAuthenticationFilter.class)
|
||||
.sessionManagement()
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
|
||||
}
|
||||
|
||||
private LoginAuthenticationFilter buildFormLoginFilter() throws Exception {
|
||||
final LoginAuthenticationFilter loginFilter = new LoginAuthenticationFilter("/token");
|
||||
loginFilter.setJwtService(jwtService);
|
||||
return loginFilter;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("gilman").password("password").roles("USER");
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setJwtService(JwtService jwtService) {
|
||||
this.jwtService = jwtService;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,16 +34,7 @@
|
|||
${nf.login.script.tags}
|
||||
</head>
|
||||
<body>
|
||||
<form name="loginForm" action="token" method="post">
|
||||
<legend>Please Login</legend>
|
||||
<label for="username">Username</label>
|
||||
<input type="text" id="username" name="username" value="${username}"/>
|
||||
<br>
|
||||
<label for="password">Password</label>
|
||||
<input type="password" id="password" name="password"/>
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn">Log in</button>
|
||||
</div>
|
||||
</form>
|
||||
<jsp:include page="/WEB-INF/partials/login/login-form.jsp"/>
|
||||
<jsp:include page="/WEB-INF/partials/login/registration-form.jsp"/>
|
||||
</body>
|
||||
</html>
|
|
@ -50,7 +50,7 @@
|
|||
<li>
|
||||
<span id="about-link" class="link">about</span>
|
||||
</li>
|
||||
<li>
|
||||
<li id="login-link-container">
|
||||
<span id="login-link" class="link">login</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<%--
|
||||
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.
|
||||
--%>
|
||||
<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
|
||||
<div id="login-form">
|
||||
<legend>Please Login</legend>
|
||||
<label for="username">Username</label>
|
||||
<input type="text" id="username" name="username" value="${username}"/>
|
||||
<br>
|
||||
<label for="password">Password</label>
|
||||
<input type="password" id="password" name="password"/>
|
||||
<div class="form-actions">
|
||||
<button id="login-button" type="submit" class="btn">Log in</button>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,19 @@
|
|||
<%--
|
||||
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.
|
||||
--%>
|
||||
<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
|
||||
<div id="registration-form">
|
||||
</div>
|
|
@ -42,4 +42,5 @@
|
|||
@import url(settings.css);
|
||||
@import url(about.css);
|
||||
@import url(message-pane.css);
|
||||
@import url(login.css);
|
||||
@import url(status-history.css);
|
|
@ -32,7 +32,7 @@ nf.CanvasHeader = (function () {
|
|||
/**
|
||||
* Initialize the canvas header.
|
||||
*/
|
||||
init: function () {
|
||||
init: function (supportsLogin) {
|
||||
// mouse over for the reporting link
|
||||
nf.Common.addHoverEffect('#reporting-link', 'reporting-link', 'reporting-link-hover').click(function () {
|
||||
nf.Shell.showPage('summary');
|
||||
|
@ -139,10 +139,14 @@ nf.CanvasHeader = (function () {
|
|||
nf.Shell.showPage(config.urls.helpDocument);
|
||||
});
|
||||
|
||||
// login link
|
||||
$('#login-link').click(function () {
|
||||
nf.Shell.showPage('login', false);
|
||||
});
|
||||
if (supportsLogin === true) {
|
||||
// login link
|
||||
$('#login-link').click(function () {
|
||||
nf.Shell.showPage('login', false);
|
||||
});
|
||||
} else {
|
||||
$('#login-link-container').css('display', 'none');
|
||||
}
|
||||
|
||||
// initialize the new template dialog
|
||||
$('#new-template-dialog').modal({
|
||||
|
|
|
@ -64,6 +64,7 @@ nf.Canvas = (function () {
|
|||
banners: '../nifi-api/controller/banners',
|
||||
controller: '../nifi-api/controller',
|
||||
controllerConfig: '../nifi-api/controller/config',
|
||||
loginConfig: '../nifi-api/controller/login/config',
|
||||
cluster: '../nifi-api/cluster',
|
||||
d3Script: 'js/d3/d3.min.js'
|
||||
}
|
||||
|
@ -1037,6 +1038,13 @@ nf.Canvas = (function () {
|
|||
dataType: 'json'
|
||||
});
|
||||
|
||||
// get the login config
|
||||
var loginXhr = $.ajax({
|
||||
type: 'GET',
|
||||
url: config.urls.loginConfig,
|
||||
dataType: 'json'
|
||||
});
|
||||
|
||||
// create the deferred cluster request
|
||||
var isClusteredRequest = $.Deferred(function (deferred) {
|
||||
$.ajax({
|
||||
|
@ -1063,9 +1071,10 @@ nf.Canvas = (function () {
|
|||
});
|
||||
|
||||
// ensure the authorities and config request is processed first
|
||||
$.when(authoritiesXhr, configXhr).done(function (authoritiesResult, configResult) {
|
||||
$.when(authoritiesXhr, configXhr, loginXhr).done(function (authoritiesResult, configResult, loginResult) {
|
||||
var authoritiesResponse = authoritiesResult[0];
|
||||
var configResponse = configResult[0];
|
||||
var loginResponse = loginResult[0];
|
||||
|
||||
// set the user's authorities
|
||||
nf.Common.setAuthorities(authoritiesResponse.authorities);
|
||||
|
@ -1076,6 +1085,7 @@ nf.Canvas = (function () {
|
|||
|
||||
// get the config details
|
||||
var configDetails = configResponse.config;
|
||||
var loginDetails = loginResponse.config;
|
||||
|
||||
// when both request complete, load the application
|
||||
isClusteredRequest.done(function () {
|
||||
|
@ -1095,7 +1105,7 @@ nf.Canvas = (function () {
|
|||
nf.ContextMenu.init();
|
||||
nf.CanvasToolbar.init();
|
||||
nf.CanvasToolbox.init();
|
||||
nf.CanvasHeader.init();
|
||||
nf.CanvasHeader.init(loginDetails.supportsLogin);
|
||||
nf.GraphControl.init();
|
||||
nf.Search.init();
|
||||
nf.Settings.init();
|
||||
|
|
|
@ -22,10 +22,40 @@ $(document).ready(function () {
|
|||
});
|
||||
|
||||
nf.Login = (function () {
|
||||
var loadControllerConfiguration = function () {
|
||||
return $.ajax({
|
||||
type: 'GET',
|
||||
url: '../nifi-api/controller/login/config',
|
||||
dataType: 'json'
|
||||
});
|
||||
};
|
||||
|
||||
var initializePage = function () {
|
||||
return $.Deferred(function (deferred) {
|
||||
console.log('hello there');
|
||||
deferred.resolve();
|
||||
return loadControllerConfiguration().done(function (response) {
|
||||
var config = response.config;
|
||||
|
||||
if (config.supportsLogin === true) {
|
||||
|
||||
}
|
||||
|
||||
if (config.supportsRegistration === true) {
|
||||
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var login = function () {
|
||||
var username = $('#username').val();
|
||||
var password = $('#password').val();
|
||||
|
||||
return $.ajax({
|
||||
type: 'POST',
|
||||
url: '../nifi-api/token',
|
||||
data: {
|
||||
'username': username,
|
||||
'password': password
|
||||
},
|
||||
dataType: 'json'
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -34,7 +64,13 @@ nf.Login = (function () {
|
|||
* Initializes the login page.
|
||||
*/
|
||||
init: function () {
|
||||
initializePage().done(function () {
|
||||
initializePage();
|
||||
|
||||
// handle login click
|
||||
$('#login-button').on('click', function () {
|
||||
login().done(function (response) {
|
||||
console.log(response);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue