@@ -63,14 +63,16 @@ public class AuthUtil {
6363 String scope ;
6464 @ Value ("${spring.security.oauth2.client.provider.azure-ad.mise-enabled:false}" )
6565 boolean miseEnabled ;
66+ @ Value ("${spring.security.oauth2.client.provider.azure-ad.mise-endpoint:}" )
67+ String miseEndpoint ;
6668
6769 Map <String , Boolean > urlMapping = null ;
6870 private static final org .slf4j .Logger LOGGER = LoggerFactory .getLogger (AuthUtil .class );
6971
7072 public boolean isValidToken (String token ) {
7173 LOGGER .info ("Starting token validation..." );
72- if (miseEnabled ) {
73- return validateTokenWithMISE (token );
74+ if (miseEnabled && miseEndpoint != null && ! miseEndpoint . isEmpty () ) {
75+ return validateTokenWithMISEEndpoint (token );
7476 }
7577 return validateTokenWithPublicKey (token ) && validateAudienceAndExpiredTime (token );
7678 }
@@ -118,91 +120,117 @@ private boolean validateTokenWithPublicKey(String token) {
118120 }
119121 }
120122
121- private boolean validateTokenWithMISE (String token ) {
123+ private boolean validateTokenWithMISEEndpoint (String token ) {
122124 LOGGER .info ("Starting MISE token validation..." );
123-
125+ // call MISE endpoint to validate the token
124126 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- LOGGER .info ("Initializing MISE..." );
130- // mise.assignLogMessageCallback(new Mise.ILogCallback() {...}, null);
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- // Configure MISE
151- JSONObject config = new JSONObject ();
152- JSONObject azureAd = new JSONObject ();
153- azureAd .put ("Instance" , instanceUri );
154- azureAd .put ("ClientId" , clientId );
155- azureAd .put ("TenantId" , tenantId );
156- String [] audiences = audience .split ("," );
157- azureAd .put ("Audiences" , audiences );
158- JSONObject logging = new JSONObject ();
159- logging .put ("logLevel" , "Debug" );
160- azureAd .put ("Logging" , logging );
161- config .put ("AzureAd" , azureAd );
162-
163- miseClass .getMethod ("configure" , String .class , String .class )
164- .invoke (mise , config .toString (), null );
165-
166- // MiseValidationInput miseValidationInput = new MiseValidationInput();
167- Class <?> miseValidationInputClass = Class .forName ("com.microsoft.identity.service.essentials.MiseValidationInput" );
168- Object miseValidationInput = miseValidationInputClass .getDeclaredConstructor ().newInstance ();
169-
170- miseValidationInputClass .getField ("authorizationHeader" ).set (miseValidationInput , "Bearer " + token );
171- miseValidationInputClass .getField ("originalMethodHeader" ).set (miseValidationInput , "GET" );
172- miseValidationInputClass .getField ("originalUriHeader" ).set (miseValidationInput , "https://myapi.com/api/values" );
173-
174- // try (MiseValidationResult validationResult = mise.validate(miseValidationInput)) { ... }
175- Object validationResult = miseClass .getMethod ("validate" , miseValidationInputClass )
176- .invoke (mise , miseValidationInput );
177-
178- // mise.unassignLogMessageCallback();
179- miseClass .getMethod ("unassignLogMessageCallback" )
180- .invoke (mise );
181-
182- Class <?> miseValidationResultClass = Class .forName ("com.microsoft.identity.service.essentials.MiseValidationResult" );
183- int statusCode = (int ) miseValidationResultClass .getMethod ("getHttpResponseStatusCode" ).invoke (validationResult );
184- LOGGER .info ("Status code " + statusCode );
185-
186- String errorDescription = (String ) miseValidationResultClass .getMethod ("getErrorDescription" ).invoke (validationResult );
187- if (errorDescription != null ) {
188- LOGGER .error ("Error message " + errorDescription );
189- }
190- // Close validationResult if AutoCloseable
191- if (validationResult instanceof AutoCloseable ) {
192- ((AutoCloseable ) validationResult ).close ();
193- }
194- if (statusCode != 200 ) {
195- LOGGER .error ("MISE token validation failed with status code: " + statusCode );
127+ RestTemplate restTemplateHttps = new RestTemplate (RestTemplateConfig .generateHttpRequestFactory ());
128+ HttpHeaders headers = new HttpHeaders ();
129+ headers .add ("Content-Type" , "application/json" );
130+ headers .add ("Authorization" , "Bearer " + token );
131+ headers .add ("Original-Uri" , "https://myapi.com/api/values" );
132+ headers .add ("Original-Method" , "GET" );
133+ headers .add ("X-Forwarded-For" , "1.2.3.4" );
134+ HttpEntity <HttpHeaders > entity = new HttpEntity <>(headers );
135+ ResponseEntity <JSONObject > response = restTemplateHttps .exchange (miseEndpoint , HttpMethod .POST , entity , JSONObject .class );
136+ if (response .getStatusCode ().is2xxSuccessful ()) {
137+ LOGGER .info ("MISE token validation passed" );
138+ return true ;
139+ } else {
140+ LOGGER .error ("MISE token validation failed with status code: " + response .getStatusCodeValue ());
196141 return false ;
197142 }
198- LOGGER .info ("MISE token validation passed" );
199143 } catch (Exception e ) {
200- e . printStackTrace ( );
144+ LOGGER . error ( "MISE token validation failed: " + e . getMessage () );
201145 return false ;
202146 }
203- return true ;
204147 }
205148
149+ // private boolean validateTokenWithMISE(String token) {
150+ // LOGGER.info("Starting MISE token validation...");
151+ //
152+ // try {
153+ // // Mise mise = Mise.createClient();
154+ // Class<?> miseClass = Class.forName("com.microsoft.identity.service.essentials.Mise");
155+ // Object mise = miseClass.getMethod("createClient").invoke(null);
156+ //
157+ // LOGGER.info("Initializing MISE...");
158+ // // mise.assignLogMessageCallback(new Mise.ILogCallback() {...}, null);
159+ // Class<?> iLogCallbackClass = Class.forName("com.microsoft.identity.service.essentials.Mise$ILogCallback");
160+ //
161+ // Object logCallback = java.lang.reflect.Proxy.newProxyInstance(
162+ // iLogCallbackClass.getClassLoader(),
163+ // new Class<?>[]{iLogCallbackClass},
164+ // (proxy, method, args) -> {
165+ // String methodName = method.getName();
166+ // if ("callback".equals(methodName)) {
167+ // Object level = args[0];
168+ // String message = (String) args[1];
169+ // // Print all log levels for simplicity
170+ // LOGGER.info(message);
171+ // }
172+ // return null;
173+ // }
174+ // );
175+ //
176+ // miseClass.getMethod("assignLogMessageCallback", iLogCallbackClass, Object.class)
177+ // .invoke(mise, logCallback, null);
178+ // // Configure MISE
179+ // JSONObject config = new JSONObject();
180+ // JSONObject azureAd = new JSONObject();
181+ // azureAd.put("Instance", instanceUri);
182+ // azureAd.put("ClientId", clientId);
183+ // azureAd.put("TenantId", tenantId);
184+ // String[] audiences = audience.split(",");
185+ // azureAd.put("Audiences", audiences);
186+ // JSONObject logging = new JSONObject();
187+ // logging.put("logLevel", "Debug");
188+ // azureAd.put("Logging", logging);
189+ // config.put("AzureAd", azureAd);
190+ //
191+ // miseClass.getMethod("configure", String.class, String.class)
192+ // .invoke(mise, config.toString(), null);
193+ //
194+ // // MiseValidationInput miseValidationInput = new MiseValidationInput();
195+ // Class<?> miseValidationInputClass = Class.forName("com.microsoft.identity.service.essentials.MiseValidationInput");
196+ // Object miseValidationInput = miseValidationInputClass.getDeclaredConstructor().newInstance();
197+ //
198+ // miseValidationInputClass.getField("authorizationHeader").set(miseValidationInput, "Bearer " + token);
199+ // miseValidationInputClass.getField("originalMethodHeader").set(miseValidationInput, "GET");
200+ // miseValidationInputClass.getField("originalUriHeader").set(miseValidationInput, "https://myapi.com/api/values");
201+ //
202+ // // try (MiseValidationResult validationResult = mise.validate(miseValidationInput)) { ... }
203+ // Object validationResult = miseClass.getMethod("validate", miseValidationInputClass)
204+ // .invoke(mise, miseValidationInput);
205+ //
206+ // // mise.unassignLogMessageCallback();
207+ // miseClass.getMethod("unassignLogMessageCallback")
208+ // .invoke(mise);
209+ //
210+ // Class<?> miseValidationResultClass = Class.forName("com.microsoft.identity.service.essentials.MiseValidationResult");
211+ // int statusCode = (int) miseValidationResultClass.getMethod("getHttpResponseStatusCode").invoke(validationResult);
212+ // LOGGER.info("Status code " + statusCode);
213+ //
214+ // String errorDescription = (String) miseValidationResultClass.getMethod("getErrorDescription").invoke(validationResult);
215+ // if (errorDescription != null) {
216+ // LOGGER.error("Error message " + errorDescription);
217+ // }
218+ // // Close validationResult if AutoCloseable
219+ // if (validationResult instanceof AutoCloseable) {
220+ // ((AutoCloseable) validationResult).close();
221+ // }
222+ // if (statusCode != 200) {
223+ // LOGGER.error("MISE token validation failed with status code: " + statusCode);
224+ // return false;
225+ // }
226+ // LOGGER.info("MISE token validation passed");
227+ // } catch (Exception e) {
228+ // e.printStackTrace();
229+ // return false;
230+ // }
231+ // return true;
232+ // }
233+
206234 private PublicKey getPublicKey (JWSObject jwsObject , JWKSet jwkSet ) throws JOSEException {
207235 JWSAlgorithm algorithm = jwsObject .getHeader ().getAlgorithm ();
208236 if (!algorithm .equals (JWSAlgorithm .RS256 )) {
0 commit comments