Working on SAML 2

This commit is contained in:
DarioGii
2025-02-01 23:30:28 +00:00
committed by Dario Ghunney Ware
parent 704da399d4
commit 6478674d9b
25 changed files with 339 additions and 277 deletions

View File

@@ -14,7 +14,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -110,7 +109,7 @@ public class ApplicationProperties {
private int loginAttemptCount;
private long loginResetTimeMinutes;
private String loginMethod = "all";
private String customGlobalAPIKey;
private String customGlobalAPIKey; // todo: expose?
public Boolean isAltLogin() {
return saml2.getEnabled() || oauth2.getEnabled();
@@ -139,13 +138,13 @@ public class ApplicationProperties {
|| loginMethod.equalsIgnoreCase(LoginMethods.ALL.toString()));
}
public boolean isOauth2Activ() {
public boolean isOauth2Active() {
return (oauth2 != null
&& oauth2.getEnabled()
&& !loginMethod.equalsIgnoreCase(LoginMethods.NORMAL.toString()));
}
public boolean isSaml2Activ() {
public boolean isSaml2Active() {
return (saml2 != null
&& saml2.getEnabled()
&& !loginMethod.equalsIgnoreCase(LoginMethods.NORMAL.toString()));
@@ -161,6 +160,7 @@ public class ApplicationProperties {
@Setter
@ToString
public static class SAML2 {
private String provider;
private Boolean enabled = false;
private Boolean autoCreateUser = false;
private Boolean blockRegistration = false;
@@ -198,7 +198,7 @@ public class ApplicationProperties {
}
}
public Resource getidpCert() {
public Resource getIdpCert() {
if (idpCert == null) return null;
if (idpCert.startsWith("classpath:")) {
return new ClassPathResource(idpCert.substring("classpath:".length()));
@@ -228,12 +228,11 @@ public class ApplicationProperties {
private Collection<String> scopes = new ArrayList<>();
private String provider;
private Client client = new Client();
private String logoutUrl;
public void setScopes(String scopes) {
List<String> scopesList =
Arrays.stream(scopes.split(","))
.map(String::trim)
.toList();
Arrays.stream(scopes.split(",")).map(String::trim).toList();
this.scopes.addAll(scopesList);
}
@@ -266,7 +265,9 @@ public class ApplicationProperties {
case "keycloak" -> getKeycloak();
default ->
throw new UnsupportedProviderException(
"Logout from the provider " + registrationId + " is not supported. "
"Logout from the provider "
+ registrationId
+ " is not supported. "
+ "Report it at https://github.com/Stirling-Tools/Stirling-PDF/issues");
};
}

View File

@@ -4,14 +4,17 @@ import lombok.Getter;
@Getter
public enum UsernameAttribute {
NAME("name"),
EMAIL("email"),
GIVEN_NAME("given_name"),
PREFERRED_NAME("preferred_name"),
PREFERRED_USERNAME("preferred_username"),
LOGIN("login"),
PROFILE("profile"),
NAME("name"),
USERNAME("username"),
NICKNAME("nickname"),
GIVEN_NAME("given_name"),
MIDDLE_NAME("middle_name"),
FAMILY_NAME("family_name"),
NICKNAME("nickname");
PREFERRED_NAME("preferred_name"),
PREFERRED_USERNAME("preferred_username");
private final String name;

View File

@@ -28,6 +28,7 @@ public class GitHubProvider extends Provider {
clientSecret,
scopes,
useAsUsername != null ? useAsUsername : UsernameAttribute.LOGIN,
null,
AUTHORIZATION_URI,
TOKEN_URI,
USER_INFO_URI);

View File

@@ -29,6 +29,7 @@ public class GoogleProvider extends Provider {
clientSecret,
scopes,
useAsUsername,
null,
AUTHORIZATION_URI,
TOKEN_URI,
USER_INFO_URI);

View File

@@ -28,6 +28,7 @@ public class KeycloakProvider extends Provider {
useAsUsername,
null,
null,
null,
null);
}

View File

@@ -16,6 +16,8 @@ import stirling.software.SPDF.model.exception.UnsupportedUsernameAttribute;
@NoArgsConstructor
public class Provider {
public static final String EXCEPTION_MESSAGE = "The attribute %s is not supported for %s.";
private String issuer;
private String name;
private String clientName;
@@ -23,6 +25,7 @@ public class Provider {
private String clientSecret;
private Collection<String> scopes;
private UsernameAttribute useAsUsername;
private String logoutUrl;
private String authorizationUri;
private String tokenUri;
private String userInfoUri;
@@ -35,6 +38,7 @@ public class Provider {
String clientSecret,
Collection<String> scopes,
UsernameAttribute useAsUsername,
String logoutUrl,
String authorizationUri,
String tokenUri,
String userInfoUri) {
@@ -46,6 +50,7 @@ public class Provider {
this.scopes = scopes == null ? new ArrayList<>() : scopes;
this.useAsUsername =
useAsUsername != null ? validateUsernameAttribute(useAsUsername) : EMAIL;
this.logoutUrl = logoutUrl;
this.authorizationUri = authorizationUri;
this.tokenUri = tokenUri;
this.userInfoUri = userInfoUri;
@@ -83,41 +88,29 @@ public class Provider {
}
default ->
throw new UnsupportedUsernameAttribute(
"The attribute "
+ usernameAttribute
+ "is not supported for "
+ clientName
+ ".");
String.format(EXCEPTION_MESSAGE, usernameAttribute, clientName));
}
}
private UsernameAttribute validateGoogleUsernameAttribute(UsernameAttribute usernameAttribute) {
switch (usernameAttribute) {
case EMAIL, NAME, GIVEN_NAME, PREFERRED_NAME -> {
case EMAIL, NAME, GIVEN_NAME, FAMILY_NAME -> {
return usernameAttribute;
}
default ->
throw new UnsupportedUsernameAttribute(
"The attribute "
+ usernameAttribute
+ "is not supported for "
+ clientName
+ ".");
String.format(EXCEPTION_MESSAGE, usernameAttribute, clientName));
}
}
private UsernameAttribute validateGitHubUsernameAttribute(UsernameAttribute usernameAttribute) {
switch (usernameAttribute) {
case EMAIL, NAME, LOGIN -> {
case LOGIN, EMAIL, NAME -> {
return usernameAttribute;
}
default ->
throw new UnsupportedUsernameAttribute(
"The attribute "
+ usernameAttribute
+ "is not supported for "
+ clientName
+ ".");
String.format(EXCEPTION_MESSAGE, usernameAttribute, clientName));
}
}