Skip to content

Commit 3be04b4

Browse files
zhou9584Le Zhou
andauthored
Feature: support MISE mode to valid token (#708)
<!-- Please provide brief information about the PR, what it contains & its purpose, new behaviors after the change. And let us know here if you need any help: https://github.com/microsoft/HydraLab/issues/new --> ## Description <!-- A few words to explain your changes --> ### Linked GitHub issue ID: # ## Pull Request Checklist <!-- Put an x in the boxes that apply. This is simply a reminder of what we are going to look for before merging your code. --> - [ ] Tests for the changes have been added (for bug fixes / features) - [ ] Code compiles correctly with all tests are passed. - [ ] I've read the [contributing guide](https://github.com/microsoft/HydraLab/blob/main/CONTRIBUTING.md#making-changes-to-the-code) and followed the recommended practices. - [ ] [Wikis](https://github.com/microsoft/HydraLab/wiki) or [README](https://github.com/microsoft/HydraLab/blob/main/README.md) have been reviewed and added / updated if needed (for bug fixes / features) ### Does this introduce a breaking change? *If this introduces a breaking change for Hydra Lab users, please describe the impact and migration path.* - [ ] Yes - [x] No ## How you tested it *Please make sure the change is tested, you can test it by adding UTs, do local test and share the screenshots, etc.* Please check the type of change your PR introduces: - [ ] Bugfix - [x] Feature - [ ] Technical design - [ ] Build related changes - [ ] Refactoring (no functional changes, no api changes) - [ ] Code style update (formatting, renaming) or Documentation content changes - [ ] Other (please describe): ### Feature UI screenshots or Technical design diagrams *If this is a relatively large or complex change, kick it off by drawing the tech design with PlantUML and explaining why you chose the solution you did and what alternatives you considered, etc...* --------- Co-authored-by: Le Zhou <[email protected]>
1 parent 223b0b7 commit 3be04b4

File tree

4 files changed

+123
-2
lines changed

4 files changed

+123
-2
lines changed

azure-pipelines-ci.yml

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ stages:
149149
script: |
150150
cp android_client/app/build/outputs/apk/release/app-release.apk common/src/main/resources/record_release.apk -force
151151
- task: Gradle@2
152-
displayName: Build center
152+
displayName: Build center (with MISE)
153153
inputs:
154154
gradleWrapperFile: 'gradlew'
155155
tasks: 'center:bootJar --stacktrace'
@@ -158,6 +158,8 @@ stages:
158158
jdkVersionOption: '1.11'
159159
sonarQubeRunAnalysis: false
160160
spotBugsAnalysis: false
161+
options: '-PIDDPUsername=IdentityDivision -PIDDPPassword=$(IDDPPassword) -PenableMISE=true'
162+
condition: eq(variables.fullBuild, 'true')
161163
- task: Gradle@2
162164
displayName: Build agent
163165
inputs:
@@ -205,6 +207,23 @@ stages:
205207
Contents: '*.jar'
206208
TargetFolder: '$(Build.ArtifactStagingDirectory)/center_deploy'
207209
condition: eq(variables.fullBuild, 'true')
210+
- task: Gradle@2
211+
displayName: Build center (without MISE)
212+
inputs:
213+
gradleWrapperFile: 'gradlew'
214+
tasks: 'center:bootJar --stacktrace'
215+
publishJUnitResults: false
216+
javaHomeOption: 'JDKVersion'
217+
jdkVersionOption: '1.11'
218+
sonarQubeRunAnalysis: false
219+
spotBugsAnalysis: false
220+
- task: CopyFiles@2
221+
displayName: Copy center jar
222+
inputs:
223+
SourceFolder: 'center/build/libs/'
224+
Contents: '*.jar'
225+
TargetFolder: '$(Build.ArtifactStagingDirectory)/center_publish'
226+
condition: eq(variables.fullBuild, 'true')
208227
- task: Gradle@2
209228
displayName: Package Mac installer
210229
inputs:

center/build.gradle

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,16 @@ bootJar.dependsOn("checkstyleMain")
1414

1515
repositories {
1616
mavenCentral()
17+
if (project.hasProperty("enableMISE")) {
18+
maven {
19+
url 'https://identitydivision.pkgs.visualstudio.com/_packaging/IDDP/maven/v1'
20+
name 'IDDP'
21+
credentials(PasswordCredentials)
22+
authentication {
23+
basic(BasicAuthentication)
24+
}
25+
}
26+
}
1727
}
1828

1929
bootJar {
@@ -67,6 +77,9 @@ dependencies {
6777

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

7285
import org.apache.tools.ant.taskdefs.condition.Os

center/src/main/java/com/microsoft/hydralab/center/util/AuthUtil.java

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,17 @@ public class AuthUtil {
6161
String ignoreUri;
6262
@Value("${spring.security.oauth2.client.registration.azure-client.scope:}")
6363
String scope;
64+
@Value("${spring.security.oauth2.client.provider.azure-ad.miseEnabled:false}")
65+
boolean miseEnabled;
6466

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

6870
public boolean isValidToken(String token) {
6971
LOGGER.info("Starting token validation...");
72+
if (miseEnabled) {
73+
return validateTokenWithMISE(token);
74+
}
7075
return validateTokenWithPublicKey(token) && validateAudienceAndExpiredTime(token);
7176
}
7277

@@ -113,6 +118,89 @@ private boolean validateTokenWithPublicKey(String token) {
113118
}
114119
}
115120

121+
public boolean validateTokenWithMISE(String token) {
122+
LOGGER.info("Starting MISE token validation...");
123+
124+
try {
125+
// Mise mise = Mise.createClient();
126+
Class<?> miseClass = Class.forName("com.microsoft.identity.service.essentials.Mise");
127+
Object mise = miseClass.getMethod("createClient").invoke(null);
128+
129+
// mise.assignLogMessageCallback(new Mise.ILogCallback() {...}, null);
130+
Class<?> logLevelClass = Class.forName("com.microsoft.identity.service.essentials.MiseLogLevel");
131+
Class<?> iLogCallbackClass = Class.forName("com.microsoft.identity.service.essentials.Mise$ILogCallback");
132+
133+
Object logCallback = java.lang.reflect.Proxy.newProxyInstance(
134+
iLogCallbackClass.getClassLoader(),
135+
new Class<?>[]{iLogCallbackClass},
136+
(proxy, method, args) -> {
137+
String methodName = method.getName();
138+
if ("callback".equals(methodName)) {
139+
Object level = args[0];
140+
String message = (String) args[1];
141+
// Print all log levels for simplicity
142+
LOGGER.info(message);
143+
}
144+
return null;
145+
}
146+
);
147+
148+
miseClass.getMethod("assignLogMessageCallback", iLogCallbackClass, Object.class)
149+
.invoke(mise, logCallback, null);
150+
151+
// Configure MISE
152+
JSONObject config = new JSONObject();
153+
JSONObject azureAd = new JSONObject();
154+
azureAd.put("Instance", instanceUri);
155+
azureAd.put("ClientId", clientId);
156+
azureAd.put("TenantId", tenantId);
157+
String[] audiences = audience.split(",");
158+
azureAd.put("Audiences", audiences);
159+
JSONObject logging = new JSONObject();
160+
logging.put("logLevel", "Debug");
161+
azureAd.put("Logging", logging);
162+
config.put("AzureAd", azureAd);
163+
164+
miseClass.getMethod("configure", String.class, String.class)
165+
.invoke(mise, config.toString(), null);
166+
167+
// MiseValidationInput miseValidationInput = new MiseValidationInput();
168+
Class<?> miseValidationInputClass = Class.forName("com.microsoft.identity.service.essentials.MiseValidationInput");
169+
Object miseValidationInput = miseValidationInputClass.getDeclaredConstructor().newInstance();
170+
171+
miseValidationInputClass.getField("authorizationHeader").set(miseValidationInput, "Bearer " + token);
172+
miseValidationInputClass.getField("originalMethodHeader").set(miseValidationInput, "GET");
173+
miseValidationInputClass.getField("originalUriHeader").set(miseValidationInput, "https://myapi.com/api/values");
174+
175+
// try (MiseValidationResult validationResult = mise.validate(miseValidationInput)) { ... }
176+
Object validationResult = miseClass.getMethod("validate", miseValidationInputClass)
177+
.invoke(mise, miseValidationInput);
178+
179+
Class<?> miseValidationResultClass = Class.forName("com.microsoft.identity.service.essentials.MiseValidationResult");
180+
int statusCode = (int) miseValidationResultClass.getMethod("getHttpResponseStatusCode").invoke(validationResult);
181+
LOGGER.info("Status code " + statusCode);
182+
183+
String errorDescription = (String) miseValidationResultClass.getMethod("getErrorDescription").invoke(validationResult);
184+
if (errorDescription != null) {
185+
LOGGER.error("Error message " + errorDescription);
186+
}
187+
188+
// Close validationResult if AutoCloseable
189+
if (validationResult instanceof AutoCloseable) {
190+
((AutoCloseable) validationResult).close();
191+
}
192+
if (statusCode != 200) {
193+
LOGGER.error("MISE token validation failed with status code: " + statusCode);
194+
return false;
195+
}
196+
LOGGER.info("MISE token validation passed");
197+
} catch (Exception e) {
198+
e.printStackTrace();
199+
return false;
200+
}
201+
return true;
202+
}
203+
116204
private PublicKey getPublicKey(JWSObject jwsObject, JWKSet jwkSet) throws JOSEException {
117205
JWSAlgorithm algorithm = jwsObject.getHeader().getAlgorithm();
118206
if (!algorithm.equals(JWSAlgorithm.RS256)) {
@@ -228,7 +316,7 @@ public String getLoginUserDisplayName(String accessToken) {
228316
public String getLoginUrl() {
229317
String loginUrl = authorizationUri + "?client_id=" + clientId +
230318
"&response_type=code+id_token&redirect_uri=" + redirectUri +
231-
"&response_mode=form_post&nonce="+ UUID.randomUUID() +"&scope=" + scope;
319+
"&response_mode=form_post&nonce=" + UUID.randomUUID() + "&scope=" + scope;
232320
return loginUrl;
233321
}
234322

center/src/main/resources/application-release.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ spring:
1212
tenant-id: ${MICROSOFT_PROVIDER_TENANT_ID}
1313
audience: ${MICROSOFT_PROVIDER_AUDIENCE}
1414
instance-uri: ${MICROSOFT_PROVIDER_INSTANCE_URI}
15+
mise-enabled: ${MICROSOFT_MISE_ENABLED:false}
1516
registration:
1617
azure-client:
1718
provider: azure-ad

0 commit comments

Comments
 (0)