package com.aip.gateway.api; import com.aip.gateway.api.aip.manager.AipFileManager; import com.aip.gateway.api.aip.model.AipConfig; import com.aip.gateway.api.aip.model.AipLabel; import com.aip.gateway.api.aip.model.AipTemplate; import com.aip.gateway.api.aip.utils.AipFileUtils; import com.aip.gateway.api.aip.utils.MemoryTokenCacheWithEviction; import com.google.common.base.Stopwatch; import com.microsoft.aad.msal4j.ClientCredentialFactory; import com.microsoft.aad.msal4j.ClientCredentialParameters; import com.microsoft.aad.msal4j.ConfidentialClientApplication; import com.microsoft.aad.msal4j.IAuthenticationResult; import com.nimbusds.oauth2.sdk.http.HTTPResponse; import lombok.extern.slf4j.Slf4j; import org.jasypt.encryption.pbe.PooledPBEStringEncryptor; import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig; import org.jasypt.salt.StringFixedSaltGenerator; import org.junit.jupiter.api.Test; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @Slf4j //@SpringBootTest class AipGatewayApiApplicationTests { private final String instance = "https://login.microsoftonline.com/"; private final String tenantId = "2e58414a-c6ae-43ff-aaf5-45ab8b78a404"; private final String clientId = "0e225915-3be3-419c-aa04-284d7de5e16b"; private final String scope = "https://graph.microsoft.com/.default"; private final String secret = "CvW8Q~0iANtLN1Y2EXR_nVyYb_tQTDwjW-Z7Ndg3"; private final String secretFile = "C:\\Data\\SSL\\mip\\mip_gateway.pfx"; private ConfidentialClientApplication app; @Test void test2() { String fileName = "c:\\data\\SSL\\mip\\mip_gateway.pfx"; String ext = AipFileUtils.getExtension(fileName); String name = AipFileUtils.getFileName(fileName); log.error("[{}] , [{}] [{}] [{}]", fileName, ext, name, AipFileUtils.getFileNameWithoutExtension(fileName)); } @Test void jasypt() { String encKey = "asdkjfaslkjflkajslfjkajlkf"; PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor(); SimpleStringPBEConfig config = new SimpleStringPBEConfig(); // ==> SimpleStringPBEConfig 사용시 아래 3개 반드시 설정해야함 config.setPassword(encKey); // 암호화에 사용할 키 config.setPoolSize(1); // Pool Size config.setSaltGenerator(new StringFixedSaltGenerator("fixedSalt")); // 고정으로 암호화(Default: Random) //config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator"); //config.setAlgorithm("PBEWithMD5AndTripleDES"); config.setAlgorithm("PBEWithMD5AndDES"); // Jasypt 를 이용한 암호화 알고리즘 config.setProviderName("SunJCE"); config.setKeyObtentionIterations("10000"); config.setStringOutputType("base64"); /*private Boolean proxyPropertySources = false; private String bean = "jasyptStringEncryptor"; private String password; private String algorithm = "PBEWithMD5AndDES"; private String keyObtentionIterations = "1000"; private String poolSize = "1"; private String providerName = null; //config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator"); private String saltGeneratorClassname = "org.jasypt.salt.RandomSaltGenerator"; private String stringOutputType = "base64";*/ encryptor.setConfig(config); String dbUser = encryptor.encrypt("aipuser"); String dbPswd = encryptor.encrypt("aipuser"); log.info("{}", dbUser); log.info("{}", dbPswd); } boolean AipFileInitialize(AipConfig aipConfig) { AipFileManager aipFileManager = new AipFileManager(aipConfig); if (!aipFileManager.initialize()) { log.error("AipFileManager.initialize Failed, {}, {}", aipFileManager.getLastErrNo(), aipFileManager.getLastErrMsg()); return false; } if (!aipFileManager.createProfile()) { log.error("AipFileManager.createProfile Failed, {}, {}", aipFileManager.getLastErrNo(), aipFileManager.getLastErrMsg()); return false; } if (!aipFileManager.createEngine()) { log.error("AipFileManager.createEngine Failed, {}, {}", aipFileManager.getLastErrNo(), aipFileManager.getLastErrMsg()); return false; } log.info("AipFileManager Initialize And Create Success."); List labels = aipFileManager.sensitivityLabels(); log.info("{}", labels); List policies = aipFileManager.listSensitivityLabels(); log.info("{}", policies); List templates = aipFileManager.getTemplates(); log.info("{}", templates); return true; } @Test void aipTest() { AipConfig aipConfig = AipConfig.builder() .appName("AIP Gateway RESTFull Service") .appVersion("1.0.0.0") .clientId("0e225915-3be3-419c-aa04-284d7de5e16b") .tenantId("2e58414a-c6ae-43ff-aaf5-45ab8b78a404") .mipData("App_Data\\\\mip_data") .loginType(AipConfig.authLoginCert) .domain("AIP.Gateway") .eMail("seungho@ms365.hanteinfo.com") .secretValue("CvW8Q~0iANtLN1Y2EXR_nVyYb_tQTDwjW-Z7Ndg3") .certThumbPrint("C:\\\\Data\\\\SSL\\\\mip\\\\mip_gateway.pfx") .build(); AipFileInitialize(aipConfig); } private IAuthenticationResult getAccessTokenByClientCredentialGrant(String instance, String clientId, String tenantId, String secret, String scope) throws Exception { // Setup the token cache first. It is configured to allow 100k token entries, which at 2-3KB per entry, will take under 500MB of memory // Note that size calculations are approximate and depend on the JVM String cacheKey = clientId + "_" + tenantId + "_AppTokenCache"; MemoryTokenCacheWithEviction memoryTokenCacheWithEviction = new MemoryTokenCacheWithEviction(cacheKey); ConfidentialClientApplication cca = ConfidentialClientApplication.builder( clientId, ClientCredentialFactory.createFromSecret(secret)) .authority(instance + tenantId) .setTokenCacheAccessAspect(memoryTokenCacheWithEviction) .build(); // Important: point the CCA object to a token cache ClientCredentialParameters clientCredentialParam = ClientCredentialParameters.builder( Collections.singleton(scope)) .build(); Stopwatch stopwatch = Stopwatch.createStarted(); CompletableFuture future = cca.acquireToken(clientCredentialParam); IAuthenticationResult result = future.get(); log.info("Time to fetch the token: {} ms.", stopwatch.elapsed(TimeUnit.MILLISECONDS)); return result; } private void getOrCreateApp(String clientId, String authority, String certPath) throws Exception { if (app == null) { //PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Files.readAllBytes(Paths.get(keyPath))); //PrivateKey key = KeyFactory.getInstance("RSA").generatePrivate(spec); InputStream certStream = new ByteArrayInputStream(Files.readAllBytes(Paths.get(certPath))); //X509Certificate cert = (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(certStream); String password = "hanteinfo1234!"; app = ConfidentialClientApplication.builder( clientId, ClientCredentialFactory.createFromCertificate(certStream, password)) //ClientCredentialFactory.createFromCertificate(key, cert)) .authority(authority) .build(); } } private String getUsersListFromGraph(String accessToken) throws IOException { URL url = new URL("https://graph.microsoft.com/v1.0/users"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setRequestProperty("Authorization", "Bearer " + accessToken); conn.setRequestProperty("Accept","application/json"); int httpResponseCode = conn.getResponseCode(); if(httpResponseCode == HTTPResponse.SC_OK) { StringBuilder response; try(BufferedReader in = new BufferedReader( new InputStreamReader(conn.getInputStream()))){ String inputLine; response = new StringBuilder(); while (( inputLine = in.readLine()) != null) { response.append(inputLine); } } return response.toString(); } else { return String.format("Connection returned HTTP code: %s with message: %s", httpResponseCode, conn.getResponseMessage()); } } @Test void testSecretAuth() { try { IAuthenticationResult result = getAccessTokenByClientCredentialGrant(instance, clientId, tenantId, secret, scope); // If you try to fetch the same token again, it will hit the token cache and it will be much faster. // In case AAD has an outage, cached tokens are still available, increasing your app's resiliency. result = getAccessTokenByClientCredentialGrant(instance, clientId, tenantId, secret, scope); String usersListFromGraph = getUsersListFromGraph(result.accessToken()); log.info("Users in the Tenant = {}", usersListFromGraph); System.out.println("Press any key to exit ..."); System.in.read(); } catch(Exception ex){ System.out.println("Oops! We have an exception of type - " + ex.getClass()); System.out.println("Exception message - " + ex.getMessage()); try { throw ex; } catch (Exception e) { throw new RuntimeException(e); } } } @Test void testCertFile() { try { // Ensure the app object is not re-created on each request, as it holds a token cache // If you are getting tokens for many tenants (millions), see the msal-client-credential-secret-high-availability sample // which shows how to use an in-memory token cache with eviction based on a size limit getOrCreateApp(clientId, instance+tenantId, "C:\\Data\\SSL\\mip\\mip_gateway.pfx"); ClientCredentialParameters clientCredentialParam = ClientCredentialParameters.builder( Collections.singleton(scope)) .build(); // The first time this is called, the app will make an HTTP request to the token issuer, so this is slow. Latency can be >1s IAuthenticationResult result = app.acquireToken(clientCredentialParam).get(); // On subsequent calls, the app will return a token from its cache. It is important to reuse the app object // Now that we have a Bearer token, call the protected API String usersListFromGraph = getUsersListFromGraph(result.accessToken()); System.out.println("Users in the Tenant = " + usersListFromGraph); System.out.println("Press any key to exit ..."); System.in.read(); } catch (Exception ex) { System.out.println("Oops! We have an exception of type - " + ex.getClass()); System.out.println("Exception message - " + ex.getMessage()); try { throw ex; } catch (Exception e) { throw new RuntimeException(e); } } } // @Test // void testAip() throws ExecutionException, InterruptedException { // InputStreamReader input = new InputStreamReader(System.in); // BufferedReader reader = new BufferedReader(input); // // // ApplicationInfo is used to store the application name, clientId, and version. // ApplicationInfo appInfo = new ApplicationInfo(); // FileOptions options = new FileOptions(); // // appInfo.setApplicationId("0e225915-3be3-419c-aa04-284d7de5e16b"); // appInfo.setApplicationName("MIP SDK Java Sample"); // appInfo.setApplicationVersion("1.11"); // // String userName = "shjung@ms365.hanteinfo.com"; // // Action action = new Action(appInfo, userName); // // // Fetch the list of labels for the authenticated user and display. // action.ListLabels(); // // // Copy a label Id from the output and paste into the prompt. // options.LabelId = "1098bdb0-f2bc-43d3-b9c7-e610431fc1a4"; // // // Provide an input file that should be labeled. // options.InputFilePath = "C:\\Data\\Source\\source.pptx"; // // // Provide the output path for the file. The original file remains intact and a // // copy is created. // options.OutputFilePath = "C:\\Data\\Source\\source-out.pptx"; // // // The privileged AssignmentMethod is used when users label files, and can // // override STANDARD. // options.AssignmentMethod = AssignmentMethod.PRIVILEGED; // // // Information on datastate is used to populate audit information. This field // // doesn't impact the SDK behavior. // options.DataState = DataState.REST; // // // Sets whether the sample should generate an audit event. // options.IsAuditDiscoveryEnabled = true; // // // Apply the chosen label to the input file. // // boolean result = action.SetLabel(options); // // if (result) { // // This section attempts to read the label from the file, if one was applied. // log.error("Reading label from file..."); // // options.InputFilePath = options.OutputFilePath; // // log.error("File Name: " + options.InputFilePath); // log.error("File Label: " + action.GetLabel(options).label.getName()); // // log.error("Reading owner from file..."); // log.error("File Label: " + action.GetProtection(options).getOwner()); // } // else { // log.error("No changes were written to the input file."); // } // // } }