mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-02-21 00:17:05 +01:00
Added SSOAutoLogin functionality to SAML 2 logins
This commit is contained in:
parent
8a9886c821
commit
264de0bbd7
@ -19,6 +19,7 @@ import stirling.software.SPDF.utils.GeneralUtils;
|
|||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class KeygenLicenseVerifier {
|
public class KeygenLicenseVerifier {
|
||||||
|
// todo: place in config files?
|
||||||
private static final String ACCOUNT_ID = "e5430f69-e834-4ae4-befd-b602aae5f372";
|
private static final String ACCOUNT_ID = "e5430f69-e834-4ae4-befd-b602aae5f372";
|
||||||
private static final String BASE_URL = "https://api.keygen.sh/v1/accounts";
|
private static final String BASE_URL = "https://api.keygen.sh/v1/accounts";
|
||||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
@ -67,7 +68,7 @@ public class KeygenLicenseVerifier {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Error verifying license: " + e.getMessage());
|
log.error("Error verifying license: {}", e.getMessage());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,10 +95,9 @@ public class KeygenLicenseVerifier {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
log.debug(" validateLicenseResponse body: " + response.body());
|
log.debug("ValidateLicenseResponse body: {}", response.body());
|
||||||
JsonNode jsonResponse = objectMapper.readTree(response.body());
|
JsonNode jsonResponse = objectMapper.readTree(response.body());
|
||||||
if (response.statusCode() == 200) {
|
if (response.statusCode() == 200) {
|
||||||
|
|
||||||
JsonNode metaNode = jsonResponse.path("meta");
|
JsonNode metaNode = jsonResponse.path("meta");
|
||||||
boolean isValid = metaNode.path("valid").asBoolean();
|
boolean isValid = metaNode.path("valid").asBoolean();
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ public class KeygenLicenseVerifier {
|
|||||||
log.info(applicationProperties.toString());
|
log.info(applicationProperties.toString());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
log.error("Error validating license. Status code: " + response.statusCode());
|
log.error("Error validating license. Status code: {}", response.statusCode());
|
||||||
}
|
}
|
||||||
return jsonResponse;
|
return jsonResponse;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package stirling.software.SPDF.config.security;
|
package stirling.software.SPDF.config.security;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.Optional;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@ -10,7 +10,6 @@ import org.springframework.context.annotation.DependsOn;
|
|||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.security.authentication.ProviderManager;
|
import org.springframework.security.authentication.ProviderManager;
|
||||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
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.EnableWebSecurity;
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
@ -23,16 +22,10 @@ import org.springframework.security.saml2.provider.service.web.authentication.Op
|
|||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
|
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
|
||||||
import org.springframework.security.web.context.DelegatingSecurityContextRepository;
|
|
||||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
|
||||||
import org.springframework.security.web.context.RequestAttributeSecurityContextRepository;
|
|
||||||
import org.springframework.security.web.context.SecurityContextRepository;
|
|
||||||
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
|
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
|
||||||
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
|
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
|
||||||
import org.springframework.security.web.savedrequest.NullRequestCache;
|
import org.springframework.security.web.savedrequest.NullRequestCache;
|
||||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationFailureHandler;
|
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationFailureHandler;
|
||||||
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationSuccessHandler;
|
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationSuccessHandler;
|
||||||
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2UserService;
|
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2UserService;
|
||||||
@ -47,7 +40,6 @@ import stirling.software.SPDF.repository.PersistentLoginRepository;
|
|||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
@EnableMethodSecurity
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@DependsOn("runningEE")
|
@DependsOn("runningEE")
|
||||||
public class SecurityConfiguration {
|
public class SecurityConfiguration {
|
||||||
@ -104,7 +96,7 @@ public class SecurityConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http, SecurityContextRepository securityContextRepository) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
if (applicationProperties.getSecurity().getCsrfDisabled() || !loginEnabledValue) {
|
if (applicationProperties.getSecurity().getCsrfDisabled() || !loginEnabledValue) {
|
||||||
http.csrf(csrf -> csrf.disable());
|
http.csrf(csrf -> csrf.disable());
|
||||||
}
|
}
|
||||||
@ -264,13 +256,6 @@ public class SecurityConfiguration {
|
|||||||
authenticationProvider.setResponseAuthenticationConverter(
|
authenticationProvider.setResponseAuthenticationConverter(
|
||||||
new CustomSaml2ResponseAuthenticationConverter(userService));
|
new CustomSaml2ResponseAuthenticationConverter(userService));
|
||||||
http.authenticationProvider(authenticationProvider)
|
http.authenticationProvider(authenticationProvider)
|
||||||
.securityContext(security ->
|
|
||||||
security.securityContextRepository(
|
|
||||||
new DelegatingSecurityContextRepository(
|
|
||||||
new RequestAttributeSecurityContextRepository(),
|
|
||||||
new HttpSessionSecurityContextRepository())
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.saml2Login(
|
.saml2Login(
|
||||||
saml2 -> {
|
saml2 -> {
|
||||||
try {
|
try {
|
||||||
|
@ -27,6 +27,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import stirling.software.SPDF.SPDFApplication;
|
||||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
|
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
|
||||||
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
@ -121,7 +122,11 @@ public class AccountWebController {
|
|||||||
String saml2AuthenticationPath = "/saml2/authenticate/" + saml2.getRegistrationId();
|
String saml2AuthenticationPath = "/saml2/authenticate/" + saml2.getRegistrationId();
|
||||||
|
|
||||||
if (applicationProperties.getEnterpriseEdition().isSsoAutoLogin()) {
|
if (applicationProperties.getEnterpriseEdition().isSsoAutoLogin()) {
|
||||||
return "redirect:login" + saml2AuthenticationPath;
|
return "redirect:"
|
||||||
|
+ SPDFApplication.getStaticBaseUrl()
|
||||||
|
+ ":"
|
||||||
|
+ SPDFApplication.getStaticPort()
|
||||||
|
+ saml2AuthenticationPath;
|
||||||
} else {
|
} else {
|
||||||
providerList.put(saml2AuthenticationPath, samlIdp + " (SAML 2)");
|
providerList.put(saml2AuthenticationPath, samlIdp + " (SAML 2)");
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ public class ApplicationProperties {
|
|||||||
private int loginAttemptCount;
|
private int loginAttemptCount;
|
||||||
private long loginResetTimeMinutes;
|
private long loginResetTimeMinutes;
|
||||||
private String loginMethod = "all";
|
private String loginMethod = "all";
|
||||||
private String customGlobalAPIKey; // todo: expose?
|
private String customGlobalAPIKey;
|
||||||
|
|
||||||
public Boolean isAltLogin() {
|
public Boolean isAltLogin() {
|
||||||
return saml2.getEnabled() || oauth2.getEnabled();
|
return saml2.getEnabled() || oauth2.getEnabled();
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
|
|
||||||
security:
|
security:
|
||||||
enableLogin: true # set to 'true' to enable login
|
enableLogin: false # set to 'true' to enable login
|
||||||
csrfDisabled: false # set to 'true' to disable CSRF protection (not recommended for production)
|
csrfDisabled: false # set to 'true' to disable CSRF protection (not recommended for production)
|
||||||
loginAttemptCount: 5 # lock user account after 5 tries; when using e.g. Fail2Ban you can deactivate the function with -1
|
loginAttemptCount: 5 # lock user account after 5 tries; when using e.g. Fail2Ban you can deactivate the function with -1
|
||||||
loginResetTimeMinutes: 120 # lock account for 2 hours after x attempts
|
loginResetTimeMinutes: 120 # lock account for 2 hours after x attempts
|
||||||
@ -39,33 +39,32 @@ security:
|
|||||||
clientSecret: '' # client secret for GitHub OAuth2
|
clientSecret: '' # client secret for GitHub OAuth2
|
||||||
scopes: read:user # scope for GitHub OAuth2
|
scopes: read:user # scope for GitHub OAuth2
|
||||||
useAsUsername: login # field to use as the username for GitHub OAuth2. Available options are: [email | login | name]
|
useAsUsername: login # field to use as the username for GitHub OAuth2. Available options are: [email | login | name]
|
||||||
issuer: https://trial-6373896.okta.com/home/okta_flow_sso/0oaok4lk1nVvNBnqK697/alnbibn6b0OPFATt20g7 # set to any provider that supports OpenID Connect Discovery (/.well-known/openid-configuration) endpoint
|
issuer: '' # set to any Provider that supports OpenID Connect Discovery (/.well-known/openid-configuration) endpoint
|
||||||
clientId: 0oaok4lk4eNm6PtFD697 # client ID from your provider
|
clientId: '' # client ID from your Provider
|
||||||
clientSecret: lmwlmxFZSJ0miOoRpUAKf2jg8tVPPXhUxgL2VB-b4uJfhnk4sI02YodKWRX8fLSq # client secret from your provider
|
clientSecret: '' # client secret from your Provider
|
||||||
logoutUrl: ''
|
|
||||||
autoCreateUser: true # set to 'true' to allow auto-creation of non-existing users
|
autoCreateUser: true # set to 'true' to allow auto-creation of non-existing users
|
||||||
blockRegistration: false # set to 'true' to deny login with SSO without prior registration by an admin
|
blockRegistration: false # set to 'true' to deny login with SSO without prior registration by an admin
|
||||||
useAsUsername: username # default is 'email'; custom fields can be used as the username
|
useAsUsername: email # default is 'email'; custom fields can be used as the username
|
||||||
scopes: okta.users.read, okta.users.read.self, okta.users.manage.self, okta.groups.read # specify the scopes for which the application will request permissions
|
scopes: openid, profile, email # specify the scopes for which the application will request permissions
|
||||||
provider: google # set this to your OAuth provider's name, e.g., 'google' or 'keycloak'
|
provider: google # set this to your OAuth Provider's name, e.g., 'google' or 'keycloak'
|
||||||
saml2:
|
saml2:
|
||||||
enabled: true # Only enabled for paid enterprise clients (enterpriseEdition.enabled must be true)
|
enabled: false # Only enabled for paid enterprise clients (enterpriseEdition.enabled must be true)
|
||||||
provider: okta
|
provider: '' The name of your Provider
|
||||||
autoCreateUser: true # set to 'true' to allow auto-creation of non-existing users
|
autoCreateUser: true # set to 'true' to allow auto-creation of non-existing users
|
||||||
blockRegistration: false # set to 'true' to deny login with SSO without prior registration by an admin
|
blockRegistration: false # set to 'true' to deny login with SSO without prior registration by an admin
|
||||||
registrationId: stirlingpdf-dario-saml
|
registrationId: stirling
|
||||||
idpMetadataUri: https://trial-6373896.okta.com/app/exkomkf71reALy12X697/sso/saml/metadata # todo: remove
|
idpMetadataUri: https://dev-XXXXXXXX.okta.com/app/externalKey/sso/saml/metadata
|
||||||
idpSingleLoginUrl: https://trial-6373896.okta.com/app/trial-6373896_stirlingpdfsaml2_1/exkoot0g5ipqOF3Bo697/sso/saml # todo: remove
|
idpSingleLoginUrl: https://dev-XXXXXXXX.okta.com/app/dev-XXXXXXXX_stirlingpdf_1/externalKey/sso/saml
|
||||||
idpSingleLogoutUrl: https://trial-6373896.okta.com/app/trial-6373896_stirlingpdfsaml2_1/exkoot0g5ipqOF3Bo697/slo/saml # todo: remove
|
idpSingleLogoutUrl: https://dev-XXXXXXXX.okta.com/app/dev-XXXXXXXX_stirlingpdf_1/externalKey/slo/saml
|
||||||
idpIssuer: http://www.okta.com/exkoot0g5ipqOF3Bo697
|
idpIssuer: ''
|
||||||
idpCert: classpath:okta.cert
|
idpCert: classpath:okta.cert
|
||||||
privateKey: classpath:private_key.key
|
privateKey: classpath:saml-private-key.key
|
||||||
spCert: classpath:certificate.crt
|
spCert: classpath:saml-public-cert.crt
|
||||||
|
|
||||||
enterpriseEdition:
|
enterpriseEdition:
|
||||||
enabled: true # set to 'true' to enable enterprise edition
|
enabled: false # set to 'true' to enable enterprise edition
|
||||||
key: 00000000-0000-0000-0000-000000000000
|
key: 00000000-0000-0000-0000-000000000000
|
||||||
SSOAutoLogin: true # Enable to auto login to first provided SSO
|
SSOAutoLogin: false # Enable to auto login to first provided SSO
|
||||||
CustomMetadata:
|
CustomMetadata:
|
||||||
autoUpdateMetadata: false # set to 'true' to automatically update metadata with below values
|
autoUpdateMetadata: false # set to 'true' to automatically update metadata with below values
|
||||||
author: username # supports text such as 'John Doe' or types such as username to autopopulate with user's username
|
author: username # supports text such as 'John Doe' or types such as username to autopopulate with user's username
|
||||||
@ -82,7 +81,7 @@ legal:
|
|||||||
system:
|
system:
|
||||||
defaultLocale: en-US # set the default language (e.g. 'de-DE', 'fr-FR', etc)
|
defaultLocale: en-US # set the default language (e.g. 'de-DE', 'fr-FR', etc)
|
||||||
googlevisibility: false # 'true' to allow Google visibility (via robots.txt), 'false' to disallow
|
googlevisibility: false # 'true' to allow Google visibility (via robots.txt), 'false' to disallow
|
||||||
enableAlphaFunctionality: true # set to enable functionality which might need more testing before it fully goes live (this feature might make no changes)
|
enableAlphaFunctionality: false # set to enable functionality which might need more testing before it fully goes live (this feature might make no changes)
|
||||||
showUpdate: false # see when a new update is available
|
showUpdate: false # see when a new update is available
|
||||||
showUpdateOnlyAdmin: false # only admins can see when a new update is available, depending on showUpdate it must be set to 'true'
|
showUpdateOnlyAdmin: false # only admins can see when a new update is available, depending on showUpdate it must be set to 'true'
|
||||||
customHTMLFiles: false # enable to have files placed in /customFiles/templates override the existing template HTML files
|
customHTMLFiles: false # enable to have files placed in /customFiles/templates override the existing template HTML files
|
||||||
|
Loading…
Reference in New Issue
Block a user