introduces custom settings file (#1158)

* Introducing a custom settings file

* formats

* chnages

* Update README.md
This commit is contained in:
Anthony Stirling
2024-05-03 20:43:48 +01:00
committed by GitHub
parent fbbc71d7e6
commit 890163053b
13 changed files with 272 additions and 253 deletions

View File

@@ -1,8 +1,8 @@
package stirling.software.SPDF.config.security;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -24,6 +24,8 @@ import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.ClientRegistrations;
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
@@ -33,17 +35,15 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.savedrequest.NullRequestCache;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.oauth2.client.registration.ClientRegistrations;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.User;
import stirling.software.SPDF.repository.JPATokenRepositoryImpl;
import java.io.IOException;
import java.util.*;
@Configuration
@EnableWebSecurity()
@EnableMethodSecurity
@@ -109,7 +109,7 @@ public class SecurityConfiguration {
logout ->
logout.logoutRequestMatcher(
new AntPathRequestMatcher("/logout"))
.logoutSuccessHandler(new CustomLogoutSuccessHandler()) // Use a Custom Logout Handler to handle custom error message if OAUTH2 Auto Create is disabled
.logoutSuccessHandler(new CustomLogoutSuccessHandler())
.invalidateHttpSession(true) // Invalidate session
.deleteCookies("JSESSIONID", "remember-me")
.addLogoutHandler(
@@ -167,33 +167,45 @@ public class SecurityConfiguration {
// Handle OAUTH2 Logins
if (applicationProperties.getSecurity().getOAUTH2().getEnabled()) {
http.oauth2Login( oauth2 -> oauth2
.loginPage("/oauth2")
/*
This Custom handler is used to check if the OAUTH2 user trying to log in, already exists in the database.
If user exists, login proceeds as usual. If user does not exist, then it is autocreated but only if 'OAUTH2AutoCreateUser'
is set as true, else login fails with an error message advising the same.
*/
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws ServletException , IOException{
OAuth2User oauthUser = (OAuth2User) authentication.getPrincipal();
if (userService.processOAuth2PostLogin(oauthUser.getAttribute("email"), applicationProperties.getSecurity().getOAUTH2().getAutoCreateUser())) {
response.sendRedirect("/");
}
else{
response.sendRedirect("/logout?oauth2AutoCreateDisabled=true");
}
}
}
)
// Add existing Authorities from the database
.userInfoEndpoint( userInfoEndpoint ->
userInfoEndpoint.userAuthoritiesMapper(userAuthoritiesMapper())
)
);
}
http.oauth2Login(
oauth2 ->
oauth2.loginPage("/oauth2")
/*
This Custom handler is used to check if the OAUTH2 user trying to log in, already exists in the database.
If user exists, login proceeds as usual. If user does not exist, then it is autocreated but only if 'OAUTH2AutoCreateUser'
is set as true, else login fails with an error message advising the same.
*/
.successHandler(
new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(
HttpServletRequest request,
HttpServletResponse response,
Authentication authentication)
throws ServletException, IOException {
OAuth2User oauthUser =
(OAuth2User)
authentication
.getPrincipal();
if (userService.processOAuth2PostLogin(
oauthUser.getAttribute("email"),
applicationProperties
.getSecurity()
.getOAUTH2()
.getAutoCreateUser())) {
response.sendRedirect("/");
} else {
response.sendRedirect(
"/logout?oauth2AutoCreateDisabled=true");
}
}
})
// Add existing Authorities from the database
.userInfoEndpoint(
userInfoEndpoint ->
userInfoEndpoint.userAuthoritiesMapper(
userAuthoritiesMapper())));
}
} else {
http.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(authz -> authz.anyRequest().permitAll());
@@ -204,50 +216,59 @@ public class SecurityConfiguration {
// Client Registration Repository for OAUTH2 OIDC Login
@Bean
@ConditionalOnProperty(value = "security.oauth2.enabled" , havingValue = "true", matchIfMissing = false)
public ClientRegistrationRepository clientRegistrationRepository() {
return new InMemoryClientRegistrationRepository(this.oidcClientRegistration());
}
@ConditionalOnProperty(
value = "security.oauth2.enabled",
havingValue = "true",
matchIfMissing = false)
public ClientRegistrationRepository clientRegistrationRepository() {
return new InMemoryClientRegistrationRepository(this.oidcClientRegistration());
}
private ClientRegistration oidcClientRegistration() {
return ClientRegistrations.fromOidcIssuerLocation(applicationProperties.getSecurity().getOAUTH2().getIssuer())
.registrationId("oidc")
.clientId(applicationProperties.getSecurity().getOAUTH2().getClientId())
.clientSecret(applicationProperties.getSecurity().getOAUTH2().getClientSecret())
.scope("openid", "profile", "email")
.userNameAttributeName("email")
.clientName("OIDC")
.build();
}
private ClientRegistration oidcClientRegistration() {
return ClientRegistrations.fromOidcIssuerLocation(
applicationProperties.getSecurity().getOAUTH2().getIssuer())
.registrationId("oidc")
.clientId(applicationProperties.getSecurity().getOAUTH2().getClientId())
.clientSecret(applicationProperties.getSecurity().getOAUTH2().getClientSecret())
.scope("openid", "profile", "email")
.userNameAttributeName("email")
.clientName("OIDC")
.build();
}
/*
This following function is to grant Authorities to the OAUTH2 user from the values stored in the database.
This is required for the internal; 'hasRole()' function to give out the correct role.
*/
@Bean
@ConditionalOnProperty(value = "security.oauth2.enabled" , havingValue = "true", matchIfMissing = false)
@ConditionalOnProperty(
value = "security.oauth2.enabled",
havingValue = "true",
matchIfMissing = false)
GrantedAuthoritiesMapper userAuthoritiesMapper() {
return (authorities) -> {
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
authorities.forEach(authority -> {
// Add existing OAUTH2 Authorities
mappedAuthorities.add(new SimpleGrantedAuthority(authority.getAuthority()));
authorities.forEach(
authority -> {
// Add existing OAUTH2 Authorities
mappedAuthorities.add(new SimpleGrantedAuthority(authority.getAuthority()));
// Add Authorities from database for existing user, if user is present.
if (authority instanceof OAuth2UserAuthority oauth2Auth) {
Optional<User> userOpt = userService.findByUsernameIgnoreCase((String)oauth2Auth.getAttributes().get("email"));
if (userOpt.isPresent()) {
User user = userOpt.get();
if (user != null){
mappedAuthorities.add(new SimpleGrantedAuthority(
userService
.findRole(user)
.getAuthority()));
// Add Authorities from database for existing user, if user is present.
if (authority instanceof OAuth2UserAuthority oauth2Auth) {
Optional<User> userOpt =
userService.findByUsernameIgnoreCase(
(String) oauth2Auth.getAttributes().get("email"));
if (userOpt.isPresent()) {
User user = userOpt.get();
if (user != null) {
mappedAuthorities.add(
new SimpleGrantedAuthority(
userService.findRole(user).getAuthority()));
}
}
}
}
}
});
});
return mappedAuthorities;
};
}