-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
deconflicting tests -- separating zarf build into its own test
- Loading branch information
Showing
19 changed files
with
2,310 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# Plugin Development | ||
|
||
The Keycloak plugin is a custom plugin that is used for x509 certificate enrollment. | ||
|
||
## Requirements | ||
|
||
Working on the plugin requires JDK17+ and Maven 3.5+. | ||
|
||
```bash | ||
# local java version | ||
java -version | ||
|
||
# loval maven version | ||
mvn -version | ||
``` | ||
|
||
## Plugin Testing with Keycloak | ||
|
||
After making changes to the plugin code and verifying that unit tests are passing ( and hopefully writing some more ), test against Keycloak. | ||
|
||
See the `New uds-identity-config Image` section in the [CUSTOMIZE.md](./CUSTOMIZE.md#new-uds-identity-config-image) for building, publishing, and using the new image with `uds-core`. | ||
|
||
## Plugin Unit Testing / Code Coverage | ||
|
||
The maven surefire plugin is configured in the [pom.xml](./src/plugin/pom.xml). Some important commands that can be used when developing/testing on the plugin: | ||
|
||
> [!IMPORTANT] | ||
> `mvn` commands will need to be executed from inside of the `src/plugin` directory | ||
|Command|Description| | ||
|-------|-----------| | ||
| `mvn clean install` | Cleans up build artifacts and then builds and installs project into local maven repository. | | ||
| `mvn clean test` | Cleans up build artifacts and then compiles the source code and runs all tests in the project. | | ||
| `mvn clean test -Dtest=com.defenseunicorns.uds.keycloak.plugin.X509ToolsTest` | Same as `mvn clean test` but instead of running all tests in project, only runs the tests in designated file. | | ||
| `mvn surefire-report:report` | This command will run the `mvn clean test` and then generate the surefire-report.html file in `target/site` | | ||
|
||
### Viewing the Maven Surefire Reports | ||
|
||
```bash | ||
# maven command from src/plugin directory | ||
mvn surefire-report:report | ||
|
||
# uds command from base directory | ||
uds run dev-plugin | ||
``` | ||
|
||
Open the `src/plugin/target/site/index.html` file in your browser to view the test coverage. This will hot reload each time the site folder is rebuilt. | ||
|
||
Sometimes IDE's won't allow opening files in a browser, either download an extension for managing this or open it from file explorer. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -208,5 +208,4 @@ private static Object getX509Identity(final KeycloakSession session, final HttpR | |
} | ||
return null; | ||
} | ||
|
||
} |
167 changes: 167 additions & 0 deletions
167
...in/src/test/java/com/defenseunicorns/uds/keycloak/plugin/RegistrationValidation2Test.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
package com.defenseunicorns.uds.keycloak.plugin; | ||
|
||
import org.apache.commons.io.FilenameUtils; | ||
import org.jboss.resteasy.specimpl.MultivaluedMapImpl; | ||
import org.keycloak.authentication.FormContext; | ||
import org.keycloak.http.HttpRequest; | ||
import org.junit.Before; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.keycloak.authentication.ValidationContext; | ||
import org.keycloak.common.crypto.UserIdentityExtractor; | ||
import org.keycloak.common.crypto.CryptoIntegration; | ||
import org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel; | ||
import org.keycloak.authentication.authenticators.x509.X509ClientCertificateAuthenticator; | ||
import org.keycloak.models.*; | ||
import org.keycloak.services.validation.Validation; | ||
import org.keycloak.services.x509.X509ClientCertificateLookup; | ||
import org.keycloak.sessions.AuthenticationSessionModel; | ||
import org.keycloak.sessions.RootAuthenticationSessionModel; | ||
import org.mockito.Mock; | ||
import org.powermock.api.mockito.PowerMockito; | ||
import org.powermock.core.classloader.annotations.PowerMockIgnore; | ||
import org.powermock.core.classloader.annotations.PrepareForTest; | ||
import org.powermock.modules.junit4.PowerMockRunner; | ||
import org.yaml.snakeyaml.Yaml; | ||
|
||
import com.defenseunicorns.uds.keycloak.plugin.utils.CommonConfig; | ||
import com.defenseunicorns.uds.keycloak.plugin.utils.NewObjectProvider; | ||
import com.defenseunicorns.uds.keycloak.plugin.utils.UserModelDefaultMethodsImpl; | ||
import com.defenseunicorns.uds.keycloak.plugin.utils.Utils; | ||
|
||
import java.io.File; | ||
import java.io.FileInputStream; | ||
import java.security.GeneralSecurityException; | ||
import java.security.cert.X509Certificate; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.stream.Stream; | ||
|
||
import static com.defenseunicorns.uds.keycloak.plugin.utils.Utils.setupFileMocks; | ||
import static org.mockito.ArgumentMatchers.any; | ||
import static org.mockito.ArgumentMatchers.anyString; | ||
import static org.powermock.api.mockito.PowerMockito.mockStatic; | ||
|
||
|
||
@RunWith(PowerMockRunner.class) | ||
@PrepareForTest({ Yaml.class, FileInputStream.class, File.class, | ||
CommonConfig.class, FilenameUtils.class, NewObjectProvider.class, | ||
X509Tools.class, | ||
}) | ||
@PowerMockIgnore("javax.management.*") | ||
class RegistrationValidation2Test { | ||
|
||
@Mock | ||
KeycloakSession keycloakSession; | ||
@Mock | ||
KeycloakContext keycloakContext; | ||
@Mock | ||
AuthenticationSessionModel authenticationSessionModel; | ||
@Mock | ||
RootAuthenticationSessionModel rootAuthenticationSessionModel; | ||
@Mock | ||
HttpRequest httpRequest; | ||
@Mock | ||
RealmModel realmModel; | ||
@Mock | ||
ValidationContext validationContext; | ||
@Mock | ||
X509ClientCertificateLookup x509ClientCertificateLookup; | ||
@Mock | ||
AuthenticatorConfigModel authenticatorConfigModel; | ||
@Mock | ||
X509ClientCertificateAuthenticator x509ClientCertificateAuthenticator; | ||
@Mock | ||
UserIdentityExtractor userIdentityExtractor; | ||
@Mock | ||
UserProvider userProvider; | ||
@Mock | ||
UserModel userModel; | ||
@Mock | ||
GroupProvider groupProvider; | ||
|
||
public RegistrationValidation2Test() {} | ||
|
||
@Before | ||
public void setupMockBehavior() throws Exception { | ||
|
||
setupFileMocks(); | ||
|
||
// common mock implementations | ||
PowerMockito.when(validationContext.getSession()).thenReturn(keycloakSession); | ||
PowerMockito.when(keycloakSession.getContext()).thenReturn(keycloakContext); | ||
PowerMockito.when(keycloakSession.getContext().getAuthenticationSession()).thenReturn(authenticationSessionModel); | ||
PowerMockito.when(authenticationSessionModel.getParentSession()).thenReturn(rootAuthenticationSessionModel); | ||
PowerMockito.when(rootAuthenticationSessionModel.getId()).thenReturn("xxx"); | ||
PowerMockito.when(validationContext.getHttpRequest()).thenReturn(httpRequest); | ||
PowerMockito.when(validationContext.getRealm()).thenReturn(realmModel); | ||
PowerMockito.when(keycloakSession.groups()).thenReturn(groupProvider); | ||
|
||
// setup X509Tools | ||
PowerMockito.when(keycloakSession.getProvider(X509ClientCertificateLookup.class)).thenReturn(x509ClientCertificateLookup); | ||
|
||
// create cert array and add the cert | ||
X509Certificate[] certList = new X509Certificate[1]; | ||
X509Certificate x509Certificate2 = Utils.buildTestCertificate(); | ||
certList[0] = x509Certificate2; | ||
PowerMockito.when(x509ClientCertificateLookup.getCertificateChain(httpRequest)).thenReturn(certList); | ||
|
||
PowerMockito.when(realmModel.getAuthenticatorConfigsStream()).thenAnswer((stream) -> { | ||
return Stream.of(authenticatorConfigModel); | ||
}); | ||
|
||
// create map | ||
Map<String, String> mapSting = new HashMap<>(); | ||
mapSting.put("x509-cert-auth.mapper-selection.user-attribute-name", "test"); | ||
PowerMockito.when(authenticatorConfigModel.getConfig()).thenReturn(mapSting); | ||
|
||
PowerMockito.when(x509ClientCertificateAuthenticator | ||
.getUserIdentityExtractor(any(X509AuthenticatorConfigModel.class))).thenReturn(userIdentityExtractor); | ||
PowerMockito.when(keycloakSession.users()).thenReturn(userProvider); | ||
PowerMockito.when(userProvider.searchForUserByUserAttributeStream(any(RealmModel.class), anyString(), anyString())) | ||
.thenAnswer((stream) -> { | ||
return Stream.of(userModel); | ||
}); | ||
|
||
CryptoIntegration.init(this.getClass().getClassLoader()); | ||
} | ||
|
||
@Test | ||
public void testSuccess() { | ||
|
||
mockStatic(X509Tools.class); | ||
|
||
PowerMockito.when(X509Tools.getX509Username(any(FormContext.class))).thenReturn("something"); | ||
|
||
UserModelDefaultMethodsImpl userModelDefaultMethodsImpl = new UserModelDefaultMethodsImpl(); | ||
PowerMockito.when(validationContext.getUser()).thenReturn(userModelDefaultMethodsImpl); | ||
PowerMockito.when(validationContext.getRealm()).thenReturn(realmModel); | ||
|
||
MultivaluedMapImpl<String, String> formData = new MultivaluedMapImpl<>(); | ||
formData.add(Validation.FIELD_EMAIL, "test.user@test.bad"); | ||
|
||
PowerMockito.when(validationContext.getHttpRequest().getDecodedFormParameters()).thenReturn(formData); | ||
|
||
RegistrationValidation registrationValidation = new RegistrationValidation(); | ||
registrationValidation.success(validationContext); | ||
} | ||
|
||
@Test | ||
public void testSuccessNoX509() throws GeneralSecurityException { | ||
|
||
// force no cert | ||
PowerMockito.when(x509ClientCertificateLookup.getCertificateChain(httpRequest)).thenReturn(null); | ||
|
||
UserModelDefaultMethodsImpl userModelDefaultMethodsImpl = new UserModelDefaultMethodsImpl(); | ||
PowerMockito.when(validationContext.getUser()).thenReturn(userModelDefaultMethodsImpl); | ||
PowerMockito.when(validationContext.getRealm()).thenReturn(realmModel); | ||
|
||
MultivaluedMapImpl<String, String> formData = new MultivaluedMapImpl<>(); | ||
formData.add(Validation.FIELD_EMAIL, "test.user@test.bad"); | ||
|
||
PowerMockito.when(validationContext.getHttpRequest().getDecodedFormParameters()).thenReturn(formData); | ||
|
||
RegistrationValidation registrationValidation = new RegistrationValidation(); | ||
registrationValidation.success(validationContext); | ||
} | ||
} |
Oops, something went wrong.