Commit 70180a10 authored by LAVENIER's avatar LAVENIER
Browse files

[fix] Clean authentication configuration

[fix] Remove commented code
parent 1a03c41d
......@@ -676,7 +676,6 @@ public class DatabaseSchemaDaoImpl
sessionSettings = session.getProperties();
}
MetadataSources metadata = new MetadataSources(
new StandardServiceRegistryBuilder()
.applySettings(sessionSettings)
......
......@@ -60,9 +60,7 @@ import org.springframework.stereotype.Component;
exclude = {
LiquibaseAutoConfiguration.class,
FreeMarkerAutoConfiguration.class,
JndiConnectionFactoryAutoConfiguration.class,
//JmsAutoConfiguration.class,
//ActiveMQAutoConfiguration.class
JndiConnectionFactoryAutoConfiguration.class
},
scanBasePackages = {
"net.sumaris.core"
......
......@@ -41,9 +41,5 @@ import javax.persistence.EntityManager;
@Slf4j
public class JPAConfiguration {
/*@Bean
public JPAQueryFactory jpaQueryFactory(EntityManager em) {
return new JPAQueryFactory(em);
}*/
}
......@@ -57,6 +57,7 @@ public class PersonVO implements IUpdateDateEntityBean<Integer, Date>, IValueObj
// Workaround for issue see https://github.com/sumaris-net/sumaris-app/issues/3
// TODO: remove this, later
@Deprecated
private String mainProfile;
private Boolean hasAvatar;
......
......@@ -33,8 +33,6 @@ public final class HttpHeaders {
public static String ACCESS_CONTROL_DENY_DELETION_ENTITIES = "Access-Control-Deny-Deletion-Entities";
public static String HEADER_USER_AGENT = "User-Agent";
public static String X_APP_NAME = "X-App-Name";
public static String X_APP_VERSION = "X-App-Version";
......
......@@ -36,9 +36,7 @@ import java.io.IOException;
public class CORSFilter implements Filter {
public static String ALLOWED_HEADERS = "Accept, Accept-Language, Content-Language, Access-Control-Allow-Origin, Content-Type, "
+ HttpHeaders.AUTHORIZATION + ", "
+ HttpHeaders.X_APP_NAME + ", "
+ HttpHeaders.X_APP_VERSION;
+ HttpHeaders.AUTHORIZATION;
public static String ALLOWED_METHODS = "GET, PUT, POST, DELETE, OPTIONS";
public static String ALLOWED_CREDENTIALS = "true";
public static String MAX_AGE = "3600";
......@@ -53,7 +51,7 @@ public class CORSFilter implements Filter {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
// Add excepted headers
// Add CORS headers
setCorsHeaders(request, response);
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
......@@ -68,7 +66,7 @@ public class CORSFilter implements Filter {
}
static void setCorsHeaders(HttpServletRequest request, HttpServletResponse response) {
private void setCorsHeaders(HttpServletRequest request, HttpServletResponse response) {
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", ALLOWED_CREDENTIALS);
response.setHeader("Access-Control-Allow-Methods", ALLOWED_METHODS);
......
/*
* #%L
* SUMARiS
* %%
* Copyright (C) 2019 SUMARiS Consortium
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
package net.sumaris.server.http.filter;
import net.sumaris.core.event.config.ConfigurationEvent;
import net.sumaris.core.event.config.ConfigurationReadyEvent;
import net.sumaris.core.event.config.ConfigurationUpdatedEvent;
import net.sumaris.core.util.StringUtils;
import net.sumaris.server.config.SumarisServerConfiguration;
import net.sumaris.server.exception.ErrorCodes;
import net.sumaris.server.exception.ErrorHelper;
import net.sumaris.server.http.HttpHeaders;
import org.nuiton.version.Version;
import org.nuiton.version.VersionBuilder;
import org.springframework.context.event.EventListener;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author benoit.lavenier@e-is.pro
*/
public class HeaderVersionFilter extends GenericFilterBean {
private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
private Version appMinVersion = null;
@EventListener({ConfigurationReadyEvent.class, ConfigurationUpdatedEvent.class})
public void onConfigurationReady(ConfigurationEvent event) {
SumarisServerConfiguration config = (SumarisServerConfiguration)event.getConfiguration();
this.appMinVersion = config.getAppMinVersion();
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
// No min version to check: check has been disabled, so continue
if (appMinVersion == null) {
chain.doFilter(request, response);
return;
}
// Read headers
String appVersionHeader = request.getHeader(HttpHeaders.X_APP_VERSION);
// TODO check app Name, to skip if unknown appName ?
String userAgent = request.getHeader(HttpHeaders.USER_AGENT);
//String appNameHeader = request.getHeader(HttpHeaders.X_APP_NAME);
if (StringUtils.isBlank(appVersionHeader)) {
if (this.logger.isDebugEnabled()) {
this.logger.debug(String.format("No header '%s' found in request: cannot check if app version is compatible. Continue.",
HttpHeaders.X_APP_VERSION));
}
}
else {
if (this.logger.isDebugEnabled()) {
logger.debug(String.format("Checking header '%s': %s", HttpHeaders.X_APP_VERSION, appVersionHeader));
}
Version appVersion = null;
try {
appVersion = VersionBuilder.create(appVersionHeader).build();
} catch (Exception e) {
logger.error(String.format("Invalid version found in header '%s': %s - Expected format is 'x.y.z'", HttpHeaders.X_APP_VERSION, e.getMessage()));
}
if (appVersion != null && appVersion.before(appMinVersion)) {
handleBadVersion(request, response, appVersion);
return;
}
}
chain.doFilter(request, response);
}
protected void handleBadVersion(HttpServletRequest request, HttpServletResponse response, Version appVersion) throws IOException, ServletException {
SecurityContextHolder.clearContext();
String message = "Invalid App version. Expected: " + appMinVersion + ", actual: " + appVersion;
if (this.logger.isDebugEnabled()) {
this.logger.debug("Authentication request failed: " + message);
this.logger.debug("Updated SecurityContextHolder to contain null Authentication");
this.logger.debug("Delegating to authentication failure handler " + this.failureHandler);
}
response.setStatus(ErrorCodes.FORBIDDEN);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
String json = ErrorHelper.toJsonErrorString(ErrorCodes.BAD_APP_VERSION, message);
CORSFilter.setCorsHeaders(request, response);
response.getWriter().print(json);
}
}
......@@ -27,10 +27,9 @@ import com.google.common.collect.ImmutableMap;
import graphql.ExecutionInput;
import graphql.ExecutionResult;
import graphql.GraphQL;
import lombok.extern.slf4j.Slf4j;
import graphql.execution.SubscriptionExecutionStrategy;
import graphql.schema.GraphQLSchema;
import net.sumaris.core.exception.SumarisTechnicalException;
import lombok.extern.slf4j.Slf4j;
import net.sumaris.server.exception.ErrorCodes;
import net.sumaris.server.http.security.AuthService;
import net.sumaris.server.util.security.AuthTokenVO;
......
/*
* #%L
* SUMARiS
* %%
* Copyright (C) 2019 SUMARiS Consortium
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
package net.sumaris.server.http.security;
import com.google.common.base.Preconditions;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import javax.annotation.PostConstruct;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
/**
* Root authentication provider, that delegate auth to other providers
*/
@Slf4j
public class MultiAuthenticationProviderDelegator implements AuthenticationProvider {
private Collection<AuthenticationProvider> delegates;
public MultiAuthenticationProviderDelegator(Collection<AuthenticationProvider> delegates) {
Preconditions.checkArgument(CollectionUtils.isNotEmpty(delegates));
this.delegates = delegates;
}
@Override
public boolean supports(Class<?> aClass) {
return delegates.stream()
.anyMatch(p -> p.supports(aClass));
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
AuthenticationException firstError = null;
for (AuthenticationProvider provider : delegates) {
if (provider.supports(authentication.getClass())) {
try {
return provider.authenticate(authentication);
} catch (AuthenticationException e) {
log.debug(e.getMessage());
// Failed: but continue
if (firstError == null) firstError = e;
}
}
}
// Rethrow the first error
if (firstError != null) throw firstError;
// No error = no provider
throw new InternalAuthenticationServiceException("No authentication provider found");
}
}
......@@ -23,13 +23,12 @@ package net.sumaris.server.http.security;
*/
import net.sumaris.server.config.SumarisServerConfiguration;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
......@@ -85,7 +84,14 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(authenticationProvider());
Collection<AuthenticationProvider> delegates = applicationContext.getBeansOfType(AuthenticationProvider.class).values();
// No provider: error
if (CollectionUtils.isEmpty(delegates)) {
throw new BeanInitializationException("No authentication provider found! Please set 'spring.security.token.enabled' or 'spring.security.ldap.enabled'");
}
delegates.forEach(auth::authenticationProvider);
}
@Override
......@@ -103,12 +109,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// authenticated
.defaultAuthenticationEntryPointFor(forbiddenEntryPoint(), PROTECTED_URLS)
.and()
.authenticationProvider(authenticationProvider())
.addFilterBefore(restAuthenticationFilter(), AnonymousAuthenticationFilter.class)
// TODO BLA enable the version checked when App will manage the error (code: 553)
//.addFilterBefore(headerVersionFilter(), TokenAuthenticationFilter.class)
.authorizeRequests()
.requestMatchers(PROTECTED_URLS)
.authenticated()
......@@ -129,25 +130,6 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
return filter;
}
@Bean
@Primary
AuthenticationProvider authenticationProvider() {
Collection<AuthenticationProvider> delegates = applicationContext.getBeansOfType(AuthenticationProvider.class).values();
// No provider: error
if (delegates.size() == 0) {
throw new BeanInitializationException("No authentication provider found! Please set 'spring.security.token.enabled' or 'spring.security.ldap.enabled'");
}
// If only one provider, use it
if (delegates.size() == 1) {
return delegates.iterator().next();
}
// Create a multiple provider delegator
return new MultiAuthenticationProviderDelegator(delegates);
}
@Bean
SimpleUrlAuthenticationSuccessHandler successHandler() {
final SimpleUrlAuthenticationSuccessHandler successHandler = new SimpleUrlAuthenticationSuccessHandler();
......
......@@ -22,14 +22,9 @@ package net.sumaris.server.http.security.ldap;
* #L%
*/
import net.sumaris.core.service.administration.PersonService;
import net.sumaris.core.service.crypto.CryptoService;
import net.sumaris.core.util.StringUtils;
import net.sumaris.core.util.crypto.CryptoUtils;
import net.sumaris.server.http.security.AnonymousUserDetails;
import net.sumaris.server.http.security.AuthService;
import net.sumaris.server.http.security.AuthUserDetails;
import net.sumaris.server.util.security.AuthTokenVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
......@@ -38,7 +33,6 @@ import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.ldap.authentication.LdapAuthenticator;
import org.springframework.security.ldap.userdetails.LdapUserDetails;
import javax.annotation.Resource;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
......@@ -47,14 +41,15 @@ public class LdapAuthenticationProvider
private final String userDn;
@Resource
private AuthService authService;
private final AuthService authService;
public LdapAuthenticationProvider(LdapAuthenticator authenticator, LdapProperties properties) {
public LdapAuthenticationProvider(LdapAuthenticator authenticator, LdapProperties properties, AuthService authService) {
super(authenticator);
this.userDn = properties.getUserDn();
this.authService = authService;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// First check anonymous user
......@@ -94,7 +89,6 @@ public class LdapAuthenticationProvider
return authentication;
}
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
return authService.authenticateByUsername(username, authentication);
}
......
......@@ -22,8 +22,7 @@
package net.sumaris.server.http.security.ldap;
import net.sumaris.server.config.SumarisServerConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import net.sumaris.server.http.security.AuthService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
......@@ -32,12 +31,17 @@ import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
import org.springframework.security.ldap.authentication.BindAuthenticator;
@Configuration
@ConditionalOnProperty(name="spring.security.ldap.enabled", matchIfMissing = false, havingValue = "true")
@ConditionalOnProperty(name = "spring.security.ldap.enabled", havingValue = "true")
@EnableConfigurationProperties({LdapProperties.class})
public class LdapConfiguration {
@Autowired
private LdapProperties ldapProperties;
private final LdapProperties ldapProperties;
private final AuthService authService;
public LdapConfiguration(LdapProperties ldapProperties, AuthService authService) {
this.ldapProperties = ldapProperties;
this.authService = authService;
}
@Bean
public DefaultSpringSecurityContextSource contextSource() {
......@@ -45,10 +49,9 @@ public class LdapConfiguration {
}
@Bean
public LdapAuthenticationProvider ldapAuthenticationProvider(SumarisServerConfiguration config) {
public LdapAuthenticationProvider ldapAuthenticationProvider() {
BindAuthenticator authenticator = new BindAuthenticator(contextSource());
authenticator.setUserDnPatterns(ldapProperties.getUserDnPatterns());
return new LdapAuthenticationProvider(authenticator, ldapProperties);
return new LdapAuthenticationProvider(authenticator, ldapProperties, authService);
}
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment