Skip to content

Commit

Permalink
fix of bugs from testing of azure as IDP
Browse files Browse the repository at this point in the history
  • Loading branch information
skublik committed May 15, 2023
1 parent 5ba0260 commit fc33cfa
Show file tree
Hide file tree
Showing 14 changed files with 200 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<html xmlns:wicket="http://wicket.apache.org">
<body>
<wicket:extend>
<div wicket:id="feedbackContainer" class="feedbackContainer">
<div wicket:id="feedbackContainer" class="feedbackContainer" style="min-width: 360px">
<div wicket:id="feedback" class="messagePanel"/>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ <h4 class="text-bold text-center pb-3"><wicket:child/></h4>

<div wicket:id="csrfField"/>

<input type="submit" wicket:message="value:UserMenuPanel.logout"/>
<button type="submit" class="m-auto btn btn-link nav-link" wicket:message="title:PageBase.logout">
<i class="fas fa-power-off"></i>
<span class="pl-2">
<wicket:message key="PageBase.logout"/>
</span>
</button>
</form>
</div>
</wicket:extend>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public AbstractPageRemoteAuthenticationSelect() {
@Override
protected void initCustomLayout() {
List<IdentityProvider> providers = getProviders();
add(new ListView<IdentityProvider>(ID_PROVIDERS, providers) {
add(new ListView<>(ID_PROVIDERS, providers) {
@Override
protected void populateItem(ListItem<IdentityProvider> item) {
item.add(new ExternalLink(ID_PROVIDER, item.getModelObject().getRedirectLink(), item.getModelObject().getLinkText()));
Expand All @@ -56,13 +56,23 @@ protected void populateItem(ListItem<IdentityProvider> item) {
MidpointForm<?> form = new MidpointForm<>(ID_LOGOUT_FORM);
ModuleAuthentication actualModule = AuthUtil.getProcessingModuleIfExist();
if (actualModule != null) {
Authentication actualAuthentication = actualModule.getAuthentication();
Class<? extends Authentication> actualAuthClass = actualModule.getAuthentication().getClass();
Class<?> detailsClass = actualModule.getAuthentication().getDetails() != null ?
actualModule.getAuthentication().getDetails().getClass() : null;
String authName = actualModule.getModuleTypeName();
form.add(new VisibleBehaviour(() -> existRemoteAuthentication(actualAuthentication, authName)));
form.add(new VisibleBehaviour(() -> existRemoteAuthentication(actualAuthClass, detailsClass, authName)));
String prefix = actualModule.getPrefix();

form.add(AttributeModifier.replace("action",
(IModel<String>) () -> existRemoteAuthentication(actualAuthentication, authName) ?
SecurityUtils.getPathForLogoutWithContextPath(getRequest().getContextPath(), prefix) : ""));
(IModel<String>) () -> {
boolean exist = existRemoteAuthentication(actualAuthClass, detailsClass, authName);

if (exist) {
return SecurityUtils.getPathForLogoutWithContextPath(getRequest().getContextPath(), prefix);
}

return "";
}));
} else {
form.add(new VisibleBehaviour(() -> false));
}
Expand All @@ -74,12 +84,15 @@ protected void populateItem(ListItem<IdentityProvider> item) {

abstract protected Class<? extends Authentication> getSupportedAuthToken();

private boolean existRemoteAuthentication(Authentication actualAuth, String actualModuleName) {
private boolean existRemoteAuthentication(
Class<? extends Authentication> actualAuthClass,
Class<?> detailsClass,
String actualModuleName) {
return getClass().getAnnotation(PageDescriptor.class).authModule().equals(actualModuleName)
&& (getSupportedAuthToken().isAssignableFrom(actualAuth.getClass())
|| (actualAuth instanceof AnonymousAuthenticationToken
&& actualAuth.getDetails() != null
&& getSupportedAuthToken().isAssignableFrom(actualAuth.getDetails().getClass())));
&& (getSupportedAuthToken().isAssignableFrom(actualAuthClass)
|| (AnonymousAuthenticationToken.class.isAssignableFrom(actualAuthClass)
&& detailsClass != null
&& getSupportedAuthToken().isAssignableFrom(detailsClass)));
}

private List<IdentityProvider> getProviders() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -926,10 +926,10 @@
</xsd:appinfo>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="encryption">
<xsd:enumeration value="decryption">
<xsd:annotation>
<xsd:appinfo>
<jaxb:typesafeEnumMember name="ENCRYPTION"/>
<jaxb:typesafeEnumMember name="DECRYPTION"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:enumeration>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
*/
package com.evolveum.midpoint.authentication.impl.module.configuration;

import com.nimbusds.jose.util.Base64URL;

import java.io.Serializable;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
Expand All @@ -19,11 +21,16 @@ public class OidcAdditionalConfiguration implements Serializable {
private final String singingAlg;
private final RSAPublicKey publicKey;
private final RSAPrivateKey privateKey;
private final Base64URL thumbprint;
private final Base64URL thumbprint256;

private OidcAdditionalConfiguration(String singingAlg, RSAPublicKey publicKey, RSAPrivateKey privateKey) {
private OidcAdditionalConfiguration(
String singingAlg, RSAPublicKey publicKey, RSAPrivateKey privateKey, String thumbprint, String thumbprint256) {
this.singingAlg = singingAlg;
this.publicKey = publicKey;
this.privateKey = privateKey;
this.thumbprint = thumbprint != null ? Base64URL.encode(thumbprint) : null;
this.thumbprint256 = thumbprint256 != null ? Base64URL.encode(thumbprint256) : null;
}

public String getSingingAlg() {
Expand All @@ -38,6 +45,14 @@ public RSAPublicKey getPublicKey() {
return publicKey;
}

public Base64URL getThumbprint() {
return thumbprint;
}

public Base64URL getThumbprint256() {
return thumbprint256;
}

public static Builder builder() {
return new Builder();
}
Expand All @@ -48,6 +63,9 @@ public static final class Builder {
private RSAPublicKey publicKey;
private RSAPrivateKey privateKey;

private String thumbprint;
private String thumbprint256;

private Builder() {
}

Expand All @@ -66,8 +84,19 @@ public Builder privateKey(RSAPrivateKey privateKey) {
return this;
}

public Builder thumbprint(String thumbprint) {
this.thumbprint = thumbprint;
return this;
}

public Builder thumbprint256(String thumbprint256) {
this.thumbprint256 = thumbprint256;
return this;
}

public OidcAdditionalConfiguration build(){
return new OidcAdditionalConfiguration(this.singingAlg, this.publicKey, this.privateKey);
return new OidcAdditionalConfiguration(
this.singingAlg, this.publicKey, this.privateKey, this.thumbprint, this.thumbprint256);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;

import com.nimbusds.jose.util.Base64URL;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.cxf.common.util.Base64Exception;
import org.bouncycastle.operator.OperatorCreationException;
Expand Down Expand Up @@ -142,8 +144,6 @@ private static OidcClientModuleWebSecurityConfiguration buildInternal(OidcAuthen

clientRegistration = builder.build();

Assert.hasText(clientRegistration.getProviderDetails().getUserInfoEndpoint().getUri(), "UserInfoUri cannot be empty");

registrations.add(clientRegistration);

OidcAdditionalConfiguration.Builder additionalConfBuilder = OidcAdditionalConfiguration.builder()
Expand Down Expand Up @@ -203,6 +203,8 @@ private static void initializeProofKey(AbstractSimpleKeyType key, OidcAdditional
try {
Certificate certificate = getCertificate(key, protector);
publicKey = certificate.getPublicKey();
builder.thumbprint256(DigestUtils.sha256Hex(certificate.getEncoded()));
builder.thumbprint(DigestUtils.sha1Hex(certificate.getEncoded()));
} catch (Base64Exception | EncryptionException | CertificateException e) {
throw new OAuth2AuthenticationException(new OAuth2Error("missing_key"), "Unable get certificate from " + key, e);
}
Expand Down Expand Up @@ -231,6 +233,8 @@ private static void initializeProofKey(AbstractKeyStoreKeyType key, OidcAddition
try {
Certificate certificate = getCertificate(key, protector);
publicKey = certificate.getPublicKey();
builder.thumbprint256(DigestUtils.sha256Hex(certificate.getEncoded()));
builder.thumbprint(DigestUtils.sha1Hex(certificate.getEncoded()));
} catch (EncryptionException | CertificateException | KeyStoreException | IOException | NoSuchAlgorithmException e) {
throw new OAuth2AuthenticationException(new OAuth2Error("missing_key"), "Unable get certificate from " + key, e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.cxf.common.util.Base64Exception;
import org.apache.cxf.common.util.Base64Utility;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
Expand Down Expand Up @@ -58,12 +59,26 @@ protected static Certificate getCertificate(AbstractSimpleKeyType key, Protector
protected static Certificate getCertificate(ProtectedStringType certficate, Protector protector) throws EncryptionException, CertificateException, Base64Exception {
String clearValue = protector.decryptString(certficate);
byte[] certBytes;

if (StringUtils.isNotEmpty(clearValue) && clearValue.startsWith("-----")) {
//remove header on start
clearValue = clearValue.replaceFirst("-----", "");
clearValue = clearValue.substring(clearValue.indexOf("-----"));
clearValue = clearValue.replaceFirst("-----", "");

//remove header on end
clearValue = clearValue.substring(0, clearValue.indexOf("-----"));
clearValue = clearValue.replaceFirst("^\\s*", "");
clearValue = clearValue.replaceFirst("\\s++$", "");
}

if (Base64.isBase64(clearValue)) {
boolean isBase64Url = clearValue.contains("-") || clearValue.contains("_");
certBytes = Base64Utility.decode(clearValue, isBase64Url);
} else {
certBytes = clearValue.getBytes();
}

return CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(certBytes));
}

Expand Down Expand Up @@ -95,7 +110,7 @@ protected static PrivateKey getPrivateKey(AbstractSimpleKeyType key, Protector p
parser.close();
JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
if (obj == null) {
throw new EncryptionException("Unable to decode PEM key:" + key.getPrivateKey());
throw new EncryptionException("Unable to decode PEM key");
} else if (obj instanceof PEMEncryptedKeyPair) {

// Encrypted key - we will use provided password
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,24 +112,31 @@ private static void createRelyingPartyRegistration(RelyingPartyRegistration.Buil
String linkText = providerType.getLinkText() == null ? providerType.getEntityId() : providerType.getLinkText();
additionalConfigBuilder.nameOfUsernameAttribute(providerType.getNameOfUsernameAttribute())
.linkText(linkText);

String registrationId = StringUtils.isNotEmpty(serviceProviderType.getAliasForPath()) ? serviceProviderType.getAliasForPath() :
(StringUtils.isNotEmpty(serviceProviderType.getAlias()) ? serviceProviderType.getAlias() : serviceProviderType.getEntityId());

UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(
StringUtils.isNotBlank(publicHttpUrlPattern) ? publicHttpUrlPattern : getBasePath((HttpServletRequest) request));

UriComponentsBuilder ssoBuilder = builder.cloneBuilder();
ssoBuilder.pathSegment(AuthUtil.stripSlashes(configuration.getPrefixOfModule()) + SSO_LOCATION_URL_SUFFIX);

UriComponentsBuilder logoutBuilder = builder.cloneBuilder();
logoutBuilder.pathSegment(AuthUtil.stripSlashes(configuration.getPrefixOfModule()) + LOGOUT_LOCATION_URL_SUFFIX);

registrationBuilder
.registrationId(registrationId)
.entityId(serviceProviderType.getEntityId())
.assertionConsumerServiceLocation(ssoBuilder.build().toUriString())
.singleLogoutServiceLocation(logoutBuilder.build().toUriString())
.assertingPartyDetails(party -> {
party.entityId(providerType.getEntityId());

if (serviceProviderType.isSignRequests() != null) {
party.wantAuthnRequestsSigned(Boolean.TRUE.equals(serviceProviderType.isSignRequests()));
}

if (providerType.getVerificationKeys() != null && !providerType.getVerificationKeys().isEmpty()) {
party.verificationX509Credentials(c -> providerType.getVerificationKeys().forEach(verKey -> {
byte[] certbytes = new byte[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,18 @@ protected String determineTargetUrl(HttpServletRequest request, HttpServletRespo
if (internalAuthentication instanceof PreAuthenticatedAuthenticationToken
|| internalAuthentication instanceof AnonymousAuthenticationToken) {
Object details = internalAuthentication.getDetails();
if (details instanceof OAuth2LoginAuthenticationToken
&& ((OAuth2LoginAuthenticationToken)details).getDetails() instanceof OidcUser) {
OAuth2LoginAuthenticationToken oidcAuthentication = (OAuth2LoginAuthenticationToken) details;
String registrationId = oidcAuthentication.getClientRegistration().getRegistrationId();
ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(registrationId);
URI endSessionEndpoint = this.endSessionEndpoint(clientRegistration);
if (endSessionEndpoint != null) {
String idToken = this.idToken(oidcAuthentication);
String postLogoutRedirectUri = this.postLogoutRedirectUri(request);
targetUrl = this.endpointUri(endSessionEndpoint, idToken, postLogoutRedirectUri);
if (details instanceof OAuth2LoginAuthenticationToken) {
OidcUser oidcUser = this.getOidcUser((OAuth2LoginAuthenticationToken) details);
if (oidcUser != null) {
OAuth2LoginAuthenticationToken oidcAuthentication = (OAuth2LoginAuthenticationToken) details;
String registrationId = oidcAuthentication.getClientRegistration().getRegistrationId();
ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(registrationId);
URI endSessionEndpoint = this.endSessionEndpoint(clientRegistration);
if (endSessionEndpoint != null) {
String idToken = this.idToken(oidcUser);
String postLogoutRedirectUri = this.postLogoutRedirectUri(request);
targetUrl = this.endpointUri(endSessionEndpoint, idToken, postLogoutRedirectUri);
}
}
}
}
Expand All @@ -78,6 +80,17 @@ protected String determineTargetUrl(HttpServletRequest request, HttpServletRespo
return targetUrl != null ? targetUrl : super.determineTargetUrl(request, response);
}

private OidcUser getOidcUser(OAuth2LoginAuthenticationToken authentication) {
if (authentication.getPrincipal() instanceof OidcUser) {
return (OidcUser) authentication.getPrincipal();
}

if (authentication.getDetails() instanceof OidcUser) {
return (OidcUser) authentication.getDetails();
}
return null;
}

private URI endSessionEndpoint(ClientRegistration clientRegistration) {
if (clientRegistration != null) {
ClientRegistration.ProviderDetails providerDetails = clientRegistration.getProviderDetails();
Expand All @@ -90,8 +103,8 @@ private URI endSessionEndpoint(ClientRegistration clientRegistration) {
return null;
}

private String idToken(Authentication authentication) {
return ((OidcUser)authentication.getDetails()).getIdToken().getTokenValue();
private String idToken(OidcUser oidcUser) {
return oidcUser.getIdToken().getTokenValue();
}

private String postLogoutRedirectUri(HttpServletRequest request) {
Expand Down

0 comments on commit fc33cfa

Please sign in to comment.