Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion azure-pipelines-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ stages:
script: |
cp android_client/app/build/outputs/apk/release/app-release.apk common/src/main/resources/record_release.apk -force
- task: Gradle@2
displayName: Build center
displayName: Build center (with MISE)
inputs:
gradleWrapperFile: 'gradlew'
tasks: 'center:bootJar --stacktrace'
Expand All @@ -158,6 +158,8 @@ stages:
jdkVersionOption: '1.11'
sonarQubeRunAnalysis: false
spotBugsAnalysis: false
options: '-PIDDPUsername=IdentityDivision -PIDDPPassword=$(IDDPPassword) -PenableMISE=true'
condition: eq(variables.fullBuild, 'true')
- task: Gradle@2
displayName: Build agent
inputs:
Expand Down Expand Up @@ -205,6 +207,23 @@ stages:
Contents: '*.jar'
TargetFolder: '$(Build.ArtifactStagingDirectory)/center_deploy'
condition: eq(variables.fullBuild, 'true')
- task: Gradle@2
displayName: Build center (without MISE)
inputs:
gradleWrapperFile: 'gradlew'
tasks: 'center:bootJar --stacktrace'
publishJUnitResults: false
javaHomeOption: 'JDKVersion'
jdkVersionOption: '1.11'
sonarQubeRunAnalysis: false
spotBugsAnalysis: false
- task: CopyFiles@2
displayName: Copy center jar
inputs:
SourceFolder: 'center/build/libs/'
Contents: '*.jar'
TargetFolder: '$(Build.ArtifactStagingDirectory)/center_publish'
condition: eq(variables.fullBuild, 'true')
- task: Gradle@2
displayName: Package Mac installer
inputs:
Expand Down
13 changes: 13 additions & 0 deletions center/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ bootJar.dependsOn("checkstyleMain")

repositories {
mavenCentral()
if (project.hasProperty("enableMISE")) {
maven {
url 'https://identitydivision.pkgs.visualstudio.com/_packaging/IDDP/maven/v1'
name 'IDDP'
credentials(PasswordCredentials)
authentication {
basic(BasicAuthentication)
}
}
}
}

bootJar {
Expand Down Expand Up @@ -67,6 +77,9 @@ dependencies {

compileOnly 'org.projectlombok:lombok:1.18.20'
annotationProcessor 'org.projectlombok:lombok:1.18.20'
if (project.hasProperty("enableMISE")) {
compile(group: 'com.microsoft.identity.service.essentials', name: 'java-adapter', version: '1.32.0')
}
}

import org.apache.tools.ant.taskdefs.condition.Os
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,17 @@ public class AuthUtil {
String ignoreUri;
@Value("${spring.security.oauth2.client.registration.azure-client.scope:}")
String scope;
@Value("${spring.security.oauth2.client.provider.azure-ad.miseEnabled:false}")
boolean miseEnabled;

Map<String, Boolean> urlMapping = null;
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(AuthUtil.class);

public boolean isValidToken(String token) {
LOGGER.info("Starting token validation...");
if (miseEnabled) {
return validateTokenWithMISE(token);
}
return validateTokenWithPublicKey(token) && validateAudienceAndExpiredTime(token);
}

Expand Down Expand Up @@ -113,6 +118,89 @@ private boolean validateTokenWithPublicKey(String token) {
}
}

public boolean validateTokenWithMISE(String token) {
LOGGER.info("Starting MISE token validation...");

try {
// Mise mise = Mise.createClient();
Class<?> miseClass = Class.forName("com.microsoft.identity.service.essentials.Mise");
Object mise = miseClass.getMethod("createClient").invoke(null);

// mise.assignLogMessageCallback(new Mise.ILogCallback() {...}, null);
Class<?> logLevelClass = Class.forName("com.microsoft.identity.service.essentials.MiseLogLevel");
Class<?> iLogCallbackClass = Class.forName("com.microsoft.identity.service.essentials.Mise$ILogCallback");

Object logCallback = java.lang.reflect.Proxy.newProxyInstance(
iLogCallbackClass.getClassLoader(),
new Class<?>[]{iLogCallbackClass},
(proxy, method, args) -> {
String methodName = method.getName();
if ("callback".equals(methodName)) {
Object level = args[0];
String message = (String) args[1];
// Print all log levels for simplicity
LOGGER.info(message);
}
return null;
}
);

miseClass.getMethod("assignLogMessageCallback", iLogCallbackClass, Object.class)
.invoke(mise, logCallback, null);

// Configure MISE
JSONObject config = new JSONObject();
JSONObject azureAd = new JSONObject();
azureAd.put("Instance", instanceUri);
azureAd.put("ClientId", clientId);
azureAd.put("TenantId", tenantId);
String[] audiences = audience.split(",");
azureAd.put("Audiences", audiences);
JSONObject logging = new JSONObject();
logging.put("logLevel", "Debug");
azureAd.put("Logging", logging);
config.put("AzureAd", azureAd);

miseClass.getMethod("configure", String.class, String.class)
.invoke(mise, config.toString(), null);

// MiseValidationInput miseValidationInput = new MiseValidationInput();
Class<?> miseValidationInputClass = Class.forName("com.microsoft.identity.service.essentials.MiseValidationInput");
Object miseValidationInput = miseValidationInputClass.getDeclaredConstructor().newInstance();

miseValidationInputClass.getField("authorizationHeader").set(miseValidationInput, "Bearer " + token);
miseValidationInputClass.getField("originalMethodHeader").set(miseValidationInput, "GET");
miseValidationInputClass.getField("originalUriHeader").set(miseValidationInput, "https://myapi.com/api/values");

// try (MiseValidationResult validationResult = mise.validate(miseValidationInput)) { ... }
Object validationResult = miseClass.getMethod("validate", miseValidationInputClass)
.invoke(mise, miseValidationInput);

Class<?> miseValidationResultClass = Class.forName("com.microsoft.identity.service.essentials.MiseValidationResult");
int statusCode = (int) miseValidationResultClass.getMethod("getHttpResponseStatusCode").invoke(validationResult);
LOGGER.info("Status code " + statusCode);

String errorDescription = (String) miseValidationResultClass.getMethod("getErrorDescription").invoke(validationResult);
if (errorDescription != null) {
LOGGER.error("Error message " + errorDescription);
}

// Close validationResult if AutoCloseable
if (validationResult instanceof AutoCloseable) {
((AutoCloseable) validationResult).close();
}
if (statusCode != 200) {
LOGGER.error("MISE token validation failed with status code: " + statusCode);
return false;
}
LOGGER.info("MISE token validation passed");
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}

private PublicKey getPublicKey(JWSObject jwsObject, JWKSet jwkSet) throws JOSEException {
JWSAlgorithm algorithm = jwsObject.getHeader().getAlgorithm();
if (!algorithm.equals(JWSAlgorithm.RS256)) {
Expand Down Expand Up @@ -228,7 +316,7 @@ public String getLoginUserDisplayName(String accessToken) {
public String getLoginUrl() {
String loginUrl = authorizationUri + "?client_id=" + clientId +
"&response_type=code+id_token&redirect_uri=" + redirectUri +
"&response_mode=form_post&nonce="+ UUID.randomUUID() +"&scope=" + scope;
"&response_mode=form_post&nonce=" + UUID.randomUUID() + "&scope=" + scope;
return loginUrl;
}

Expand Down
1 change: 1 addition & 0 deletions center/src/main/resources/application-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ spring:
tenant-id: ${MICROSOFT_PROVIDER_TENANT_ID}
audience: ${MICROSOFT_PROVIDER_AUDIENCE}
instance-uri: ${MICROSOFT_PROVIDER_INSTANCE_URI}
mise-enabled: ${MICROSOFT_MISE_ENABLED:false}
registration:
azure-client:
provider: azure-ad
Expand Down
Loading