mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2024-12-21 19:08:24 +01:00
Optimierung der SAML2-Integration und Verbesserung der Zertifikats- und Fehlerbehandlung (#2105)
* certificate processing * Hides dialog when provider list is empty * removed: unused
This commit is contained in:
parent
1b88d89191
commit
d2046c64d8
@ -1,48 +1,42 @@
|
|||||||
package stirling.software.SPDF.config.security.saml2;
|
package stirling.software.SPDF.config.security.saml2;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.KeyFactory;
|
import java.security.KeyFactory;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.security.interfaces.RSAPrivateKey;
|
import java.security.interfaces.RSAPrivateKey;
|
||||||
import java.security.spec.PKCS8EncodedKeySpec;
|
import java.security.spec.PKCS8EncodedKeySpec;
|
||||||
import java.util.Base64;
|
|
||||||
|
|
||||||
|
import org.bouncycastle.util.io.pem.PemObject;
|
||||||
|
import org.bouncycastle.util.io.pem.PemReader;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.util.FileCopyUtils;
|
|
||||||
|
|
||||||
public class CertificateUtils {
|
public class CertificateUtils {
|
||||||
|
|
||||||
public static X509Certificate readCertificate(Resource certificateResource) throws Exception {
|
public static X509Certificate readCertificate(Resource certificateResource) throws Exception {
|
||||||
String certificateString =
|
try (PemReader pemReader =
|
||||||
new String(
|
new PemReader(
|
||||||
FileCopyUtils.copyToByteArray(certificateResource.getInputStream()),
|
new InputStreamReader(
|
||||||
StandardCharsets.UTF_8);
|
certificateResource.getInputStream(), StandardCharsets.UTF_8))) {
|
||||||
String certContent =
|
PemObject pemObject = pemReader.readPemObject();
|
||||||
certificateString
|
byte[] decodedCert = pemObject.getContent();
|
||||||
.replace("-----BEGIN CERTIFICATE-----", "")
|
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||||
.replace("-----END CERTIFICATE-----", "")
|
return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(decodedCert));
|
||||||
.replaceAll("\\R", "")
|
}
|
||||||
.replaceAll("\\s+", "");
|
|
||||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
|
||||||
byte[] decodedCert = Base64.getDecoder().decode(certContent);
|
|
||||||
return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(decodedCert));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RSAPrivateKey readPrivateKey(Resource privateKeyResource) throws Exception {
|
public static RSAPrivateKey readPrivateKey(Resource privateKeyResource) throws Exception {
|
||||||
String privateKeyString =
|
try (PemReader pemReader =
|
||||||
new String(
|
new PemReader(
|
||||||
FileCopyUtils.copyToByteArray(privateKeyResource.getInputStream()),
|
new InputStreamReader(
|
||||||
StandardCharsets.UTF_8);
|
privateKeyResource.getInputStream(), StandardCharsets.UTF_8))) {
|
||||||
String privateKeyContent =
|
PemObject pemObject = pemReader.readPemObject();
|
||||||
privateKeyString
|
byte[] decodedKey = pemObject.getContent();
|
||||||
.replace("-----BEGIN PRIVATE KEY-----", "")
|
return (RSAPrivateKey)
|
||||||
.replace("-----END PRIVATE KEY-----", "")
|
KeyFactory.getInstance("RSA")
|
||||||
.replaceAll("\\R", "")
|
.generatePrivate(new PKCS8EncodedKeySpec(decodedKey));
|
||||||
.replaceAll("\\s+", "");
|
}
|
||||||
KeyFactory kf = KeyFactory.getInstance("RSA");
|
|
||||||
byte[] decodedKey = Base64.getDecoder().decode(privateKeyContent);
|
|
||||||
return (RSAPrivateKey) kf.generatePrivate(new PKCS8EncodedKeySpec(decodedKey));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,10 +89,9 @@ public class AccountWebController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SAML2 saml2 = securityProps.getSaml2();
|
SAML2 saml2 = securityProps.getSaml2();
|
||||||
if (saml2 != null) {
|
if (securityProps.isSaml2Activ()
|
||||||
if (saml2.getEnabled()) {
|
&& applicationProperties.getSystem().getEnableAlphaFunctionality()) {
|
||||||
providerList.put("/saml2/authenticate/" + saml2.getRegistrationId(), "SAML 2");
|
providerList.put("/saml2/authenticate/" + saml2.getRegistrationId(), "SAML 2");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Remove any null keys/values from the providerList
|
// Remove any null keys/values from the providerList
|
||||||
providerList
|
providerList
|
||||||
@ -101,7 +100,8 @@ public class AccountWebController {
|
|||||||
model.addAttribute("providerlist", providerList);
|
model.addAttribute("providerlist", providerList);
|
||||||
|
|
||||||
model.addAttribute("loginMethod", securityProps.getLoginMethod());
|
model.addAttribute("loginMethod", securityProps.getLoginMethod());
|
||||||
model.addAttribute("altLogin", securityProps.isAltLogin());
|
boolean altLogin = providerList.size() > 0 ? securityProps.isAltLogin() : false;
|
||||||
|
model.addAttribute("altLogin", altLogin);
|
||||||
|
|
||||||
model.addAttribute("currentPage", "login");
|
model.addAttribute("currentPage", "login");
|
||||||
|
|
||||||
@ -164,6 +164,17 @@ public class AccountWebController {
|
|||||||
case "userIsDisabled":
|
case "userIsDisabled":
|
||||||
erroroauth = "login.userIsDisabled";
|
erroroauth = "login.userIsDisabled";
|
||||||
break;
|
break;
|
||||||
|
case "invalid_destination":
|
||||||
|
erroroauth = "login.invalid_destination";
|
||||||
|
break;
|
||||||
|
// Valid InResponseTo was not available from the validation context, unable to
|
||||||
|
// evaluate
|
||||||
|
case "invalid_in_response_to":
|
||||||
|
erroroauth = "login.invalid_in_response_to";
|
||||||
|
break;
|
||||||
|
case "not_authentication_provider_found":
|
||||||
|
erroroauth = "login.not_authentication_provider_found";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -283,25 +283,5 @@
|
|||||||
</script>
|
</script>
|
||||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||||
</div>
|
</div>
|
||||||
<div th:if="${altLogin}" class="modal fade" id="editUserModal" tabindex="-1" role="dialog" aria-labelledby="editUserModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title" id="editUserModalLabel" th:text="#{login.ssoSignIn}"></h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">
|
|
||||||
<span class="material-symbols-rounded">close</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="mb-3" th:each="provider : ${providerlist}">
|
|
||||||
<a th:href="@{|/oauth2/authorization/${provider.key}|}" th:text="${provider.value}" class="w-100 btn btn-lg btn-primary">OpenID Connect</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" th:text="#{close}"></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
Loading…
Reference in New Issue
Block a user