├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Integrated-Windows-Auth-Flow ├── README.md ├── ReadmeFiles │ └── Topology.png ├── pom.xml └── src │ └── main │ ├── java │ └── IntegratedWindowsAuthFlow.java │ └── resources │ └── application.properties ├── LICENSE.md ├── README.md ├── SECURITY.md └── Username-Password-Flow ├── .gitignore ├── AppCreationScripts ├── AppCreationScripts.md ├── Cleanup.ps1 ├── Configure.ps1 └── apps.json ├── README.md ├── ReadmeFiles └── Java-Native-Diagram.png ├── pom.xml └── src └── main ├── java └── UsernamePasswordFlow.java └── resources └── application.properties /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Azure samples 2 | 3 | Thank you for your interest in contributing to Azure samples! 4 | 5 | # Contributing to [project-title] 6 | 7 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 8 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 9 | the rights to use your contribution. For details, visit https://cla.microsoft.com. 10 | 11 | When you submit a pull request, a CLA-bot will automatically determine whether you need to provide 12 | a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions 13 | provided by the bot. You will only need to do this once across all repos using our CLA. 14 | 15 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 16 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 17 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 18 | 19 | - [Code of Conduct](#coc) 20 | - [Issues and Bugs](#issue) 21 | - [Feature Requests](#feature) 22 | - [Submission Guidelines](#submit) 23 | 24 | ## Code of Conduct 25 | Help us keep this project open and inclusive. Please read and follow our [Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 26 | 27 | ## Found an Issue? 28 | If you find a bug in the source code or a mistake in the documentation, you can help us by 29 | [submitting an issue](#submit-issue) to the GitHub Repository. Even better, you can 30 | [submit a Pull Request](#submit-pr) with a fix. 31 | 32 | ## Want a Feature? 33 | You can *request* a new feature by [submitting an issue](#submit-issue) to the GitHub 34 | Repository. If you would like to *implement* a new feature, please submit an issue with 35 | a proposal for your work first, to be sure that we can use it. 36 | 37 | * **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr). 38 | 39 | ## Submission Guidelines 40 | 41 | ### Submitting an Issue 42 | Before you submit an issue, search the archive, maybe your question was already answered. 43 | 44 | If your issue appears to be a bug, and hasn't been reported, open a new issue. 45 | Help us to maximize the effort we can spend fixing issues and adding new 46 | features, by not reporting duplicate issues. Providing the following information will increase the 47 | chances of your issue being dealt with quickly: 48 | 49 | * **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps 50 | * **Version** - what version is affected (e.g. 0.1.2) 51 | * **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you 52 | * **Browsers and Operating System** - is this a problem with all browsers? 53 | * **Reproduce the Error** - provide a live example or a unambiguous set of steps 54 | * **Related Issues** - has a similar issue been reported before? 55 | * **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be 56 | causing the problem (line of code or commit) 57 | 58 | You can file new issues by providing the above information at the corresponding repository's issues link: https://github.com/[organization-name]/[repository-name]/issues/new]. 59 | 60 | ### Submitting a Pull Request (PR) 61 | Before you submit your Pull Request (PR) consider the following guidelines: 62 | 63 | * Search the repository (https://github.com/[organization-name]/[repository-name]/pulls) for an open or closed PR 64 | that relates to your submission. You don't want to duplicate effort. 65 | 66 | * Make your changes in a new git fork: 67 | 68 | * Commit your changes using a descriptive commit message 69 | * Push your fork to GitHub: 70 | * In GitHub, create a pull request 71 | * If we suggest changes then: 72 | * Make the required updates. 73 | * Rebase your fork and force push to your GitHub repository (this will update your Pull Request): 74 | 75 | ```shell 76 | git rebase master -i 77 | git push -f 78 | ``` 79 | 80 | That's it! Thank you for your contribution! 81 | 82 | -------------------------------------------------------------------------------- /Integrated-Windows-Auth-Flow/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | services: active-directory 3 | platforms: Java 4 | endpoint: Microsoft identity platform 5 | page_type: sample 6 | languages: 7 | - Java 8 | author: ramya25 9 | products: 10 | - azure 11 | - azure-active-directory 12 | - Java 13 | - office-ms-graph 14 | description: "This sample demonstrates how to use MSAL4J to sign-in users using windows Integrated Auth (WIA) in apps that run on a domain joined or AAD joined Windows machine." 15 | urlFragment: Integrated-Windows-Auth-Flow 16 | --- 17 | 18 | # Invoking an API protected by Microsoft identity platform with users signed-in with Integrated Windows Authentication, on a Windows domain joined or AAD joined machine 19 | 20 | ## About this sample 21 | 22 | ### Overview 23 | 24 | This sample demonstrates how to use MSAL4J for apps running on a domain joined or AAD joined Windows machine that wish to authenticate using Windows Integrated Authentication It enables these apps to: 25 | 26 | - Authenticate the user signed-in on the Windows machine 27 | - Call a web API (in this case, the [Microsoft Graph](https://graph.microsoft.com)) 28 | 29 | ![Topology](./ReadmeFiles/Topology.png) 30 | 31 | If you would like to get started immediately, skip this section and jump to *How To Run The Sample*. 32 | 33 | ### Scenario 34 | 35 | The application obtains tokens through Integrated Windows Authentication (Kerberos): 36 | 37 | - Developers who wish to gain good familiarity of programming for Microsoft Graph are advised to go through the [An introduction to Microsoft Graph for developers](https://www.youtube.com/watch?v=EBbnpFdB92A) recorded session. 38 | 39 | ## How to run this sample 40 | 41 | To run this sample, you'll need: 42 | 43 | - Working installation of Java and Maven 44 | - An Azure Active Directory (Azure AD) tenant. For more information on how to get an Azure AD tenant, see [How to get an Azure AD tenant](https://azure.microsoft.com/documentation/articles/active-directory-howto-tenant/) 45 | - One or more user accounts in your Azure AD tenant. 46 | 47 | ### Step 1: Download Java (8 and above) for your platform 48 | 49 | To successfully use this sample, you need a working installation of [Java](https://openjdk.java.net/install/) and [Maven](https://maven.apache.org/). 50 | 51 | ### Step 2: Clone or download this repository 52 | 53 | From your shell or command line: 54 | 55 | ```Shell 56 | git clone https://github.com/Azure-Samples/ms-identity-java-desktop.git 57 | cd "Integrated-Windows-Auth-Flow" 58 | ``` 59 | 60 | or download and extract the repository .zip file. 61 | 62 | ### Step 3: Register the sample with your Azure Active Directory tenant 63 | 64 | To register the project, you can follow the steps in the paragraphs below: 65 | 66 | #### Choose the Azure AD tenant where you want to create your applications 67 | 68 | As a first step you'll need to: 69 | 70 | 1. Sign in to the [Azure portal](https://portal.azure.com) using either a work or school account or a personal Microsoft account. 71 | 1. If your account is present in more than one Azure AD tenant, select your profile at the top right corner in the menu on top of the page, and then **switch directory**. 72 | Change your portal session to the desired Azure AD tenant. 73 | 1. In the portal menu, select the **Azure Active Directory** service, and then select **App registrations**. 74 | 75 | > In the next steps, you might need the tenant name (or directory name) or the tenant ID (or directory ID). These are presented in the **Properties** of the Azure Active Directory window respectively as *Name* and *Directory ID* 76 | 77 | #### Register the client app (iwa-console) 78 | 79 | 1. Navigate to the Microsoft identity platform for developers [App registrations](https://go.microsoft.com/fwlink/?linkid=2083908) page. 80 | 1. Select **New registration**. 81 | - In the **Name** section, enter a meaningful application name that will be displayed to users of the app, for example `iwa-console`. 82 | - In the **Supported account types** section, select **Accounts in any organizational directory**. 83 | - Click **Register** button at the bottom to create the application. 84 | 1. On the application **Overview** page, find the **Application (client) ID** and **Directory (tenant) ID** values and record it for later. You'll need it to configure the configuration file(s) later in your code. 85 | 1. In the list of pages for the app, select **Manifest**, and: 86 | - In the manifest editor, set the **allowPublicClient** property to **true** 87 | - Select **Save** in the bar above the manifest editor. 88 | 1. In the list of pages for the app, select **API permissions** 89 | - Click the **Add a permission** button and then, 90 | - Ensure that the **Microsoft APIs** tab is selected 91 | - In the *Commonly used Microsoft APIs* section, click on **Microsoft Graph** 92 | - In the **Delegated permissions** section, ensure that the right permissions are checked: **User.Read**, **User.ReadBasic.All**. Use the search box if necessary. 93 | - Select the **Add permissions** button 94 | 95 | 1. At this stage permissions are assigned correctly but the client app does not allow interaction. Therefore no consent can be presented via a UI and accepted to use the service app. 96 | Click the **Grant/revoke admin consent for {tenant}** button, and then select **Yes** when you are asked if you want to grant consent for the requested permissions for all account in the tenant. 97 | You need to be an Azure AD tenant admin to do this. 98 | 99 | ### Step 4: Configure the sample to use your Azure AD tenant 100 | 101 | 1. Open the `src\main\resources\application.properties` file 102 | 1. Set the `CLIENT_ID` property to the client ID value you recorded earlier 103 | 1. Set the `USER_NAME` property to your `Windows signed-in user ID` 104 | 105 | ### Step 5: Run the sample 106 | 107 | From your shell or command line: 108 | 109 | - `$ mvn clean compile assembly:single` 110 | 111 | This will generate a `public-client-integrated-windows-authentication-sample-1.0.0.jar` file in your /targets directory. Run this using your Java executable like below: 112 | 113 | - `$ java -jar public-client-integrated-windows-authentication-sample-1.0.0.jar` 114 | 115 | ### You're done 116 | 117 | ### You're done 118 | 119 | Simply run the .jar file as described in step 5 or run the main method of `IntegratedWindowsAuthFlow.java` in your IDE to watch the sample acquire a token for the user you configured. 120 | 121 | ### About the code 122 | 123 | The code to acquire a token is located entirely in `src\main\java\IntegratedWindowsAuthFlow.Java`. The public client application is created using the **MSAL build pattern**, by passing the Application ID, an authority, and an implementation of the token cache interface. 124 | 125 | ```java 126 | PublicClientApplication pca = PublicClientApplication.builder(clientId) 127 | .authority(authority) 128 | .setTokenCacheAccessAspect(tokenCacheAspect) 129 | .build(); 130 | ``` 131 | 132 | A call to acquire the token is first made using the public client application, by creating a `SilentParameters` object to send to the application's `acquireTokenSilently()` method. The `SilentParameters` builder takes in an account (taken from the token cache) and a set of scopes. `acquireTokenSilently()` retrieves that account's token from the cache if one exists and isn't expired. If the token is expired, an attempt to retireve a new token is made if the cache contains a refresh token. 133 | 134 | If there is no token in the cache for the given account or some issue occurs when trying to use a refresh token, the code falls back to the username/password flow described below 135 | 136 | ```java 137 | SilentParameters silentParameters = 138 | SilentParameters 139 | .builder(scope) 140 | .account(account) 141 | .build(); 142 | 143 | result = pca.acquireTokenSilently(silentParameters).join(); 144 | 145 | ``` 146 | 147 | A call to acquire the token is first made using the public client application, by creating an `IntegratedWindowsAuthenticationParameters` object to send to the application's `acquireToken()` method. The `IntegratedWindowsAuthenticationParameters` builder takes in the username of a user and a set of scopes. `acquireToken()` attempts to acquires a token from the authority configured in the application via the Integrated Windows Authentication flow. 148 | 149 | ```java 150 | IntegratedWindowsAuthenticationParameters parameters = 151 | IntegratedWindowsAuthenticationParameters 152 | .builder(scope, username) 153 | .build(); 154 | 155 | result = pca.acquireToken(parameters).join(); 156 | ``` 157 | 158 | ## Community Help and Support 159 | 160 | Use [Stack Overflow](http://stackoverflow.com/questions/tagged/msal) to get support from the community. 161 | Ask your questions on Stack Overflow first and browse existing issues to see if someone has asked your question before. 162 | Make sure that your questions or comments are tagged with [`msal` `java`]. 163 | 164 | If you find a bug in the sample, please raise the issue on [GitHub Issues](../../issues). 165 | 166 | To provide a recommendation, visit the following [User Voice page](https://feedback.azure.com/forums/169401-azure-active-directory). 167 | 168 | ## Contributing 169 | 170 | If you'd like to contribute to this sample, see [CONTRIBUTING.MD](/CONTRIBUTING.md). 171 | 172 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information, see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 173 | 174 | ## More information 175 | 176 | For more information, see MSAL4J [conceptual documentation](https://github.com/AzureAD/microsoft-authentication-library-for-java/wiki). 177 | 178 | - [Integrated Windows Authentication](https://github.com/AzureAD/microsoft-authentication-library-for-java/wiki/Integrated-Windows-Authentication) 179 | - [Quickstart: Configure a client application to access web APIs](https://docs.microsoft.com/azure/active-directory/develop/quickstart-configure-app-access-web-apis) 180 | - [Understanding Azure AD application consent experiences](https://docs.microsoft.com/azure/active-directory/develop/application-consent-experience) 181 | - [Understand user and admin consent](https://docs.microsoft.com/azure/active-directory/develop/howto-convert-app-to-be-multi-tenant#understand-user-and-admin-consent) 182 | - About how OAuth 2.0 protocols work in this scenario and other scenarios, see [Authentication Scenarios for Azure AD](http://go.microsoft.com/fwlink/?LinkId=394414). 183 | 184 | - [Customizing Token cache serialization](https://docs.microsoft.com/azure/active-directory/develop/msal-java-token-cache-serialization) (was not done in this sample, but you might want to add a serialized cache) 185 | 186 | For more information about the Microsoft identity platform endpoint see: 187 | - [https://aka.ms/aadv2](https://aka.ms/aadv2) -------------------------------------------------------------------------------- /Integrated-Windows-Auth-Flow/ReadmeFiles/Topology.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/ms-identity-java-desktop/da27a1af6064d5e833e645e5040a5120a0c2698f/Integrated-Windows-Auth-Flow/ReadmeFiles/Topology.png -------------------------------------------------------------------------------- /Integrated-Windows-Auth-Flow/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.microsoft.azure 5 | public-client-integrated-windows-authentication-sample 6 | jar 7 | 1.0.0 8 | public-client-integrated-windows-authentication-sample 9 | 10 | 11 | 12 | com.microsoft.azure 13 | msal4j 14 | 1.10.1 15 | 16 | 17 | org.slf4j 18 | slf4j-simple 19 | 1.7.29 20 | 21 | 22 | 23 | 24 | 25 | 26 | org.apache.maven.plugins 27 | maven-compiler-plugin 28 | 3.8.1 29 | 30 | 8 31 | 8 32 | 33 | 34 | 35 | maven-assembly-plugin 36 | 37 | 38 | package 39 | 40 | single 41 | 42 | 43 | 44 | 45 | 46 | 47 | IntegratedWindowsAuthFlow 48 | 49 | 50 | 51 | jar-with-dependencies 52 | 53 | false 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Integrated-Windows-Auth-Flow/src/main/java/IntegratedWindowsAuthFlow.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | import com.microsoft.aad.msal4j.IAccount; 5 | import com.microsoft.aad.msal4j.IAuthenticationResult; 6 | import com.microsoft.aad.msal4j.IntegratedWindowsAuthenticationParameters; 7 | import com.microsoft.aad.msal4j.MsalException; 8 | import com.microsoft.aad.msal4j.PublicClientApplication; 9 | import com.microsoft.aad.msal4j.SilentParameters; 10 | 11 | import java.io.FileInputStream; 12 | import java.io.IOException; 13 | import java.util.Collections; 14 | import java.util.Properties; 15 | import java.util.Set; 16 | 17 | public class IntegratedWindowsAuthFlow { 18 | 19 | private static String authority; 20 | private static Set scope; 21 | private static String clientId; 22 | private static String username; 23 | 24 | public static void main(String args[]) throws Exception { 25 | 26 | setUpSampleData(); 27 | 28 | PublicClientApplication pca = PublicClientApplication.builder(clientId) 29 | .authority(authority) 30 | .build(); 31 | 32 | Set accountsInCache = pca.getAccounts().join(); 33 | IAccount account = getAccountByUsername(accountsInCache, username); 34 | 35 | //Attempt to acquire token when user's account is not in the application's token cache 36 | IAuthenticationResult result = acquireTokenIntegratedWindowsAuth(pca, scope, account, username); 37 | System.out.println("Account username: " + result.account().username()); 38 | System.out.println("Access token: " + result.accessToken()); 39 | System.out.println("Id token: " + result.idToken()); 40 | System.out.println(); 41 | 42 | //Get list of accounts from the application's token cache, and search them for the configured username 43 | //getAccounts() will be empty on this first call, as accounts are added to the cache when acquiring a token 44 | accountsInCache = pca.getAccounts().join(); 45 | account = getAccountByUsername(accountsInCache, username); 46 | 47 | //Attempt to acquire token again, now that the user's account and a token are in the application's token cache 48 | result = acquireTokenIntegratedWindowsAuth(pca, scope, account, username); 49 | System.out.println("Account username: " + result.account().username()); 50 | System.out.println("Access token: " + result.accessToken()); 51 | System.out.println("Id token: " + result.idToken()); 52 | } 53 | 54 | private static IAuthenticationResult acquireTokenIntegratedWindowsAuth( PublicClientApplication pca, 55 | Set scope, 56 | IAccount account, 57 | String username) throws Exception { 58 | 59 | IAuthenticationResult result; 60 | try { 61 | SilentParameters silentParameters = 62 | SilentParameters 63 | .builder(scope) 64 | .account(account) 65 | .build(); 66 | // Try to acquire token silently. This will fail on the first acquireTokenIntegratedWindowsAuth() call 67 | // because the token cache does not have any data for the user you are trying to acquire a token for 68 | result = pca.acquireTokenSilently(silentParameters).join(); 69 | System.out.println("==acquireTokenSilently call succeeded"); 70 | } catch (Exception ex) { 71 | if (ex.getCause() instanceof MsalException) { 72 | System.out.println("==acquireTokenSilently call failed: " + ex.getCause()); 73 | IntegratedWindowsAuthenticationParameters parameters = 74 | IntegratedWindowsAuthenticationParameters 75 | .builder(scope, username) 76 | .build(); 77 | 78 | // Try to acquire a token using Integrated Windows Authentication (IWA). You will need to generate a Kerberos ticket. 79 | // If successful, you should see the token and account information printed out to console 80 | result = pca.acquireToken(parameters).join(); 81 | System.out.println("==Integrated Windows Authentication flow succeeded"); 82 | } else { 83 | // Handle other exceptions accordingly 84 | throw ex; 85 | } 86 | } 87 | return result; 88 | } 89 | 90 | /** 91 | * Helper function to return an account from a given set of accounts based on the given username, 92 | * or return null if no accounts in the set match 93 | */ 94 | private static IAccount getAccountByUsername(Set accounts, String username) { 95 | if (accounts.isEmpty()) { 96 | System.out.println("==No accounts in cache"); 97 | } else { 98 | System.out.println("==Accounts in cache: " + accounts.size()); 99 | for (IAccount account : accounts) { 100 | if (account.username().equals(username)) { 101 | return account; 102 | } 103 | } 104 | } 105 | return null; 106 | } 107 | 108 | /** 109 | * Helper function unique to this sample setting. In a real application these wouldn't be so hardcoded, for example 110 | * values such as username would come from the user, and different users may require different scopes 111 | */ 112 | private static void setUpSampleData() throws IOException { 113 | // Load properties file and set properties used throughout the sample 114 | Properties properties = new Properties(); 115 | properties.load(new FileInputStream(Thread.currentThread().getContextClassLoader().getResource("").getPath() + "application.properties")); 116 | authority = properties.getProperty("AUTHORITY"); 117 | scope = Collections.singleton(properties.getProperty("SCOPE")); 118 | clientId = properties.getProperty("CLIENT_ID"); 119 | username = properties.getProperty("USER_NAME"); 120 | } 121 | } -------------------------------------------------------------------------------- /Integrated-Windows-Auth-Flow/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | CLIENT_ID= 2 | USER_NAME= 3 | 4 | # The below properties do not need to be changed for this sample to work. 5 | # In a real situation they would be used to affect authentication behavior, such as changing where token requests are 6 | # sent by using a different authority 7 | AUTHORITY=https://login.microsoftonline.com/organizations/ 8 | SCOPE=user.read -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A desktop application in Java calling Microsoft Graph API 2 | 3 | ## About these samples 4 | 5 | ### Overview 6 | 7 | Two samples are available: 8 | 9 | 1. Java application letting users sign-in with username/password 10 | - Source code can be found in the [Username-Password-Flow](Username-Password-Flow) directory, along with a [README](Username-Password-Flow/README.md) for configuring and running the sample 11 | 1. Java application which uses Integrated Windows Authentication to authenticate users signed into a domain joined or AAD joined machine 12 | - Source code can be found in the [Integrated-Windows-Auth-Flow](Integrated-Windows-Auth-Flow) directory, along with a [README](Integrated-Windows-Auth-Flow/README.md) for configuring and running the sample 13 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /Username-Password-Flow/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # Intellij files 26 | .idea/ 27 | *.iml 28 | -------------------------------------------------------------------------------- /Username-Password-Flow/AppCreationScripts/AppCreationScripts.md: -------------------------------------------------------------------------------- 1 | # Registering the Azure Active Directory applications and updating the configuration files for this sample using PowerShell scripts 2 | 3 | ## Goal of the scripts 4 | 5 | ### Presentation of the scripts 6 | 7 | This sample comes with two PowerShell scripts, which automate the creation of the Azure Active Directory applications, and the configuration of the code for this sample. Once you run them, you will only need to build the solution and you are good to test. 8 | 9 | These scripts are: 10 | 11 | - `Configure.ps1` which: 12 | - creates Azure AD applications and their related objects (permissions, dependencies, secrets), 13 | - changes the configuration files in the Java projects. 14 | - creates a summary file named `createdApps.html` in the folder from which you ran the script, and containing, for each Azure AD application it created: 15 | - the identifier of the application 16 | - the AppId of the application 17 | - the url of its registration in the [Azure portal](https://portal.azure.com). 18 | 19 | - `Cleanup.ps1` which cleans-up the Azure AD objects created by `Configure.ps1`. Note that this script does not revert the changes done in the configuration files, though. You will need to undo the change from source control (from the command line using, for instance, git reset). 20 | 21 | ### Usage pattern for tests and DevOps scenarios 22 | 23 | The `Configure.ps1` will stop if it tries to create an Azure AD application which already exists in the tenant. For this, if you are using the script to try/test the sample, or in DevOps scenarios, you might want to run `Cleanup.ps1` just before `Configure.ps1`. This is what is shown in the steps below. 24 | 25 | ## How to use the app creation scripts ? 26 | 27 | ### Pre-requisites 28 | 29 | To use the app creation scripts: 30 | 31 | 1. Open PowerShell (On Windows, press `Windows-R` and type `PowerShell` in the search window) 32 | 2. Navigate to the root directory of the project. 33 | 3. Until you change it, the default Execution Policy for scripts is usually `Restricted`. In order to run the PowerShell script you need to set the Execution Policy to `Unrestricted`. You can set this just for the current PowerShell process by running the command: 34 | ```PowerShell 35 | Set-ExecutionPolicy -Scope Process -ExecutionPolicy Unrestricted 36 | ``` 37 | 4. If you have never done it already, in the PowerShell window, install the AzureAD PowerShell modules. For this: 38 | 39 | 1. Open PowerShell as admin (On Windows, Search Powershell in the search bar, right click on it and select Run as administrator). 40 | 2. Type: 41 | ```PowerShell 42 | Install-Module AzureAD 43 | ``` 44 | 5. Go to the `AppCreationScripts` sub-folder. From the folder where you cloned the repo, 45 | ```PowerShell 46 | cd AppCreationScripts 47 | ``` 48 | 6. Run the scripts. See below for the [four options](#four-ways-to-run-the-script) to do that. 49 | 50 | You're done. this just works! 51 | 52 | ### Four ways to run the script 53 | 54 | We advise four ways of running the script: 55 | 56 | - Interactive: you will be prompted for credentials, and the scripts decide in which tenant to create the objects, 57 | - non-interactive: you will provide crendentials, and the scripts decide in which tenant to create the objects, 58 | - Interactive in specific tenant: you will be prompted for credentials, and the scripts decide in which tenant to create the objects, 59 | - non-interactive in specific tenant: you will provide crendentials, and the scripts decide in which tenant to create the objects. 60 | 61 | Here are the details on how to do this. 62 | 63 | #### Option 1 (interactive) 64 | 65 | - Just run ``. .\Configure.ps1``, and you will be prompted to sign-in (email address, password, and if needed MFA). 66 | - The script will be run as the signed-in user and will use the tenant in which the user is defined. 67 | 68 | Note that the script will choose the tenant in which to create the applications, based on the user. Also to run the `Cleanup.ps1` script, you will need to re-sign-in. 69 | 70 | #### Option 2 (non-interactive) 71 | 72 | When you know the indentity and credentials of the user in the name of whom you want to create the applications, you can use the non-interactive approach. It's more adapted to DevOps. Here is an example of script you'd want to run in a PowerShell Window 73 | 74 | ```PowerShell 75 | $secpasswd = ConvertTo-SecureString "[Password here]" -AsPlainText -Force 76 | $mycreds = New-Object System.Management.Automation.PSCredential ("[login@tenantName here]", $secpasswd) 77 | . .\Cleanup.ps1 -Credential $mycreds 78 | . .\Configure.ps1 -Credential $mycreds 79 | ``` 80 | 81 | Of course, in real life, you might already get the password as a `SecureString`. You might also want to get the password from KeyVault. 82 | 83 | #### Option 3 (Interactive, but create apps in a specified tenant) 84 | 85 | if you want to create the apps in a particular tenant, you can use the following option: 86 | - open the [Azure portal](https://portal.azure.com) 87 | - Select the Azure Active directory you are interested in (in the combo-box below your name on the top right of the browser window) 88 | - Find the "Active Directory" object in this tenant 89 | - Go to **Properties** and copy the content of the **Directory Id** property 90 | - Then use the full syntax to run the scripts: 91 | 92 | ```PowerShell 93 | $tenantId = "yourTenantIdGuid" 94 | . .\Cleanup.ps1 -TenantId $tenantId 95 | . .\Configure.ps1 -TenantId $tenantId 96 | ``` 97 | 98 | #### Option 4 (non-interactive, and create apps in a specified tenant) 99 | 100 | This option combines option 2 and option 3: it creates the application in a specific tenant. See option 3 for the way to get the tenant Id. Then run: 101 | 102 | ```PowerShell 103 | $secpasswd = ConvertTo-SecureString "[Password here]" -AsPlainText -Force 104 | $mycreds = New-Object System.Management.Automation.PSCredential ("[login@tenantName here]", $secpasswd) 105 | $tenantId = "yourTenantIdGuid" 106 | . .\Cleanup.ps1 -Credential $mycreds -TenantId $tenantId 107 | . .\Configure.ps1 -Credential $mycreds -TenantId $tenantId 108 | ``` 109 | -------------------------------------------------------------------------------- /Username-Password-Flow/AppCreationScripts/Cleanup.ps1: -------------------------------------------------------------------------------- 1 | param([Parameter(Mandatory=$false)][PSCredential]$Credential=$null, [Parameter(Mandatory=$false)][string]$TenantId) 2 | Import-Module AzureAD 3 | $ErrorActionPreference = 'Stop' 4 | 5 | Function Cleanup 6 | { 7 | <# 8 | .Description 9 | This function removes the Azure AD applications for the sample. These applications were created by the Configure.ps1 script 10 | #> 11 | [CmdletBinding()] 12 | param( 13 | [Parameter(HelpMessage='Tenant ID (This is a GUID which represents the "Directory ID" of the AzureAD tenant into which you want to create the apps')] 14 | [PSCredential] $Credential, 15 | [string] $tenantId 16 | ) 17 | 18 | process 19 | { 20 | # $tenantId is the Active Directory Tenant. This is a GUID which represents the "Directory ID" of the AzureAD tenant 21 | # into which you want to create the apps. Look it up in the Azure portal in the "Properties" of the Azure AD. 22 | 23 | # Login to Azure PowerShell (interactive if credentials are not already provided: 24 | # you'll need to sign-in with creds enabling your to create apps in the tenant) 25 | if (!$Credential -and $TenantId) 26 | { 27 | $creds = Connect-AzureAD -TenantId $tenantId 28 | } 29 | else 30 | { 31 | if (!$TenantId) 32 | { 33 | $creds = Connect-AzureAD -Credential $Credential 34 | } 35 | else 36 | { 37 | $creds = Connect-AzureAD -TenantId $tenantId -Credential $Credential 38 | } 39 | } 40 | 41 | if (!$tenantId) 42 | { 43 | $tenantId = $creds.Tenant.Id 44 | } 45 | $tenant = Get-AzureADTenantDetail 46 | $tenantName = ($tenant.VerifiedDomains | Where { $_._Default -eq $True }).Name 47 | 48 | # Removes the applications 49 | Write-Host "Cleaning-up applications from tenant '$tenantName'" 50 | 51 | Write-Host "Removing 'app' (Native-Headless-Application) if needed" 52 | $app=Get-AzureADApplication -Filter "DisplayName eq 'Native-Headless-Application'" 53 | if ($app) 54 | { 55 | Remove-AzureADApplication -ObjectId $app.ObjectId 56 | Write-Host "Removed." 57 | } 58 | 59 | } 60 | } 61 | 62 | Cleanup -Credential $Credential -tenantId $TenantId 63 | -------------------------------------------------------------------------------- /Username-Password-Flow/AppCreationScripts/Configure.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | This script creates the Azure AD applications needed for this sample and updates the configuration files 3 | for the visual Studio projects from the data in the Azure AD applications. 4 | 5 | Before running this script you need to install the AzureAD cmdlets as an administrator. 6 | For this: 7 | 1) Run Powershell as an administrator 8 | 2) in the PowerShell window, type: Install-Module AzureAD 9 | 10 | There are four ways to run this script. For more information, read the AppCreationScripts.md file in the same folder as this script. 11 | #> 12 | 13 | # Adds the requiredAccesses (expressed as a pipe separated string) to the requiredAccess structure 14 | # The exposed permissions are in the $exposedPermissions collection, and the type of permission (Scope | Role) is 15 | # described in $permissionType 16 | Function AddResourcePermission($requiredAccess, ` 17 | $exposedPermissions, [string]$requiredAccesses, [string]$permissionType) 18 | { 19 | foreach($permission in $requiredAccesses.Trim().Split("|")) 20 | { 21 | foreach($exposedPermission in $exposedPermissions) 22 | { 23 | if ($exposedPermission.Value -eq $permission) 24 | { 25 | $resourceAccess = New-Object Microsoft.Open.AzureAD.Model.ResourceAccess 26 | $resourceAccess.Type = $permissionType # Scope = Delegated permissions | Role = Application permissions 27 | $resourceAccess.Id = $exposedPermission.Id # Read directory data 28 | $requiredAccess.ResourceAccess.Add($resourceAccess) 29 | } 30 | } 31 | } 32 | } 33 | 34 | # 35 | # Exemple: GetRequiredPermissions "Microsoft Graph" "Graph.Read|User.Read" 36 | # See also: http://stackoverflow.com/questions/42164581/how-to-configure-a-new-azure-ad-application-through-powershell 37 | Function GetRequiredPermissions([string] $applicationDisplayName, [string] $requiredDelegatedPermissions, [string]$requiredApplicationPermissions, $servicePrincipal) 38 | { 39 | # If we are passed the service principal we use it directly, otherwise we find it from the display name (which might not be unique) 40 | if ($servicePrincipal) 41 | { 42 | $sp = $servicePrincipal 43 | } 44 | else 45 | { 46 | $sp = Get-AzureADServicePrincipal -Filter "DisplayName eq '$applicationDisplayName'" 47 | } 48 | $appid = $sp.AppId 49 | $requiredAccess = New-Object Microsoft.Open.AzureAD.Model.RequiredResourceAccess 50 | $requiredAccess.ResourceAppId = $appid 51 | $requiredAccess.ResourceAccess = New-Object System.Collections.Generic.List[Microsoft.Open.AzureAD.Model.ResourceAccess] 52 | 53 | # $sp.Oauth2Permissions | Select Id,AdminConsentDisplayName,Value: To see the list of all the Delegated permissions for the application: 54 | if ($requiredDelegatedPermissions) 55 | { 56 | AddResourcePermission $requiredAccess -exposedPermissions $sp.Oauth2Permissions -requiredAccesses $requiredDelegatedPermissions -permissionType "Scope" 57 | } 58 | 59 | # $sp.AppRoles | Select Id,AdminConsentDisplayName,Value: To see the list of all the Application permissions for the application 60 | if ($requiredApplicationPermissions) 61 | { 62 | AddResourcePermission $requiredAccess -exposedPermissions $sp.AppRoles -requiredAccesses $requiredApplicationPermissions -permissionType "Role" 63 | } 64 | return $requiredAccess 65 | } 66 | 67 | 68 | Function UpdateLine([string] $line, [string] $value) 69 | { 70 | $index = $line.IndexOf(':') 71 | $delimiter = ',' 72 | if ($index -eq -1) 73 | { 74 | $index = $line.IndexOf('=') 75 | $delimiter = ';' 76 | } 77 | if ($index -ige 0) 78 | { 79 | $line = $line.Substring(0, $index+1) + " "+'"'+$value+'"'+$delimiter 80 | } 81 | return $line 82 | } 83 | 84 | Function UpdateTextFile([string] $configFilePath, [System.Collections.HashTable] $dictionary) 85 | { 86 | $lines = Get-Content $configFilePath 87 | $index = 0 88 | while($index -lt $lines.Length) 89 | { 90 | $line = $lines[$index] 91 | foreach($key in $dictionary.Keys) 92 | { 93 | if ($line.Contains($key)) 94 | { 95 | $lines[$index] = UpdateLine $line $dictionary[$key] 96 | } 97 | } 98 | $index++ 99 | } 100 | 101 | Set-Content -Path $configFilePath -Value $lines -Force 102 | } 103 | 104 | Set-Content -Value "" -Path createdApps.html 105 | Add-Content -Value "" -Path createdApps.html 106 | 107 | Function ConfigureApplications 108 | { 109 | <#.Description 110 | This function creates the Azure AD applications for the sample in the provided Azure AD tenant and updates the 111 | configuration files in the client and service project of the visual studio solution (App.Config and Web.Config) 112 | so that they are consistent with the Applications parameters 113 | #> 114 | [CmdletBinding()] 115 | param( 116 | [PSCredential] $Credential, 117 | [Parameter(HelpMessage='Tenant ID (This is a GUID which represents the "Directory ID" of the AzureAD tenant into which you want to create the apps')] 118 | [string] $tenantId 119 | ) 120 | 121 | process 122 | { 123 | # $tenantId is the Active Directory Tenant. This is a GUID which represents the "Directory ID" of the AzureAD tenant 124 | # into which you want to create the apps. Look it up in the Azure portal in the "Properties" of the Azure AD. 125 | 126 | # Login to Azure PowerShell (interactive if credentials are not already provided: 127 | # you'll need to sign-in with creds enabling your to create apps in the tenant) 128 | if (!$Credential -and $TenantId) 129 | { 130 | $creds = Connect-AzureAD -TenantId $tenantId 131 | } 132 | else 133 | { 134 | if (!$TenantId) 135 | { 136 | $creds = Connect-AzureAD -Credential $Credential 137 | } 138 | else 139 | { 140 | $creds = Connect-AzureAD -TenantId $tenantId -Credential $Credential 141 | } 142 | } 143 | 144 | if (!$tenantId) 145 | { 146 | $tenantId = $creds.Tenant.Id 147 | } 148 | $tenant = Get-AzureADTenantDetail 149 | $tenantName = ($tenant.VerifiedDomains | Where { $_._Default -eq $True }).Name 150 | 151 | # Create the app AAD application 152 | Write-Host "Creating the AAD appplication (Native-Headless-Application)" 153 | $appAadApplication = New-AzureADApplication -DisplayName "Native-Headless-Application" ` 154 | -ReplyUrls "https://Native-Headless-Application" ` 155 | -PublicClient $True 156 | 157 | 158 | $currentAppId = $appAadApplication.AppId 159 | $appServicePrincipal = New-AzureADServicePrincipal -AppId $currentAppId -Tags {WindowsAzureActiveDirectoryIntegratedApp} 160 | Write-Host "Done." 161 | 162 | # URL of the AAD application in the Azure portal 163 | $appPortalUrl = "https://portal.azure.com/#@"+$tenantName+"/blade/Microsoft_AAD_IAM/ApplicationBlade/appId/"+$appAadApplication.AppId+"/objectId/"+$appAadApplication.ObjectId 164 | Add-Content -Value "" -Path createdApps.html 165 | 166 | $requiredResourcesAccess = New-Object System.Collections.Generic.List[Microsoft.Open.AzureAD.Model.RequiredResourceAccess] 167 | # Add Required Resources Access (from 'app' to 'Microsoft Graph') 168 | Write-Host "Getting access from 'app' to 'Microsoft Graph'" 169 | $requiredPermissions = GetRequiredPermissions -applicationDisplayName "Microsoft Graph" ` 170 | -requiredDelegatedPermissions "User.Read"; 171 | $requiredResourcesAccess.Add($requiredPermissions) 172 | Set-AzureADApplication -ObjectId $appAadApplication.ObjectId -RequiredResourceAccess $requiredResourcesAccess 173 | Write-Host "Granted." 174 | 175 | # Update config file for 'app' 176 | $configFile = $pwd.Path + "\..\src\main\java\UsernamePasswordFlow.java" 177 | Write-Host "Updating the sample code ($configFile)" 178 | $dictionary = @{ "private final static String APP_ID" = $appAadApplication.AppId }; 179 | UpdateTextFile -configFilePath $configFile -dictionary $dictionary 180 | Write-Host "" 181 | Write-Host "IMPORTANT: Think of completing the following manual step(s) in the Azure portal": 182 | Write-Host "- For 'app'" 183 | Write-Host " - Navigate to '$appPortalUrl'" 184 | Write-Host " - click Settings > Required permissions > Grant Permissions" 185 | Add-Content -Value "
ApplicationAppIdUrl in the Azure portal
app$currentAppIdNative-Headless-Application
" -Path createdApps.html 186 | 187 | } 188 | } 189 | 190 | 191 | # Run interactively (will ask you for the tenant ID) 192 | ConfigureApplications -Credential $Credential -tenantId $TenantId -------------------------------------------------------------------------------- /Username-Password-Flow/AppCreationScripts/apps.json: -------------------------------------------------------------------------------- 1 | { 2 | "Sample": { 3 | "Title": "Integrating Azure AD into a Java command line using username and password", 4 | "Level": 200, 5 | "Client": "Java Console Application", 6 | "Service": "Microsoft Graph" 7 | }, 8 | 9 | 10 | /* 11 | This section describes the Azure AD Applications to configure, and their dependencies 12 | */ 13 | "AADApps": [ 14 | { 15 | "Id": "app", 16 | "Name": "Native-Headless-Application", 17 | "IsPublicClient": true, 18 | "RequiredResourcesAccess": [ 19 | { 20 | "Resource": "Microsoft Graph", 21 | "DelegatedPermissions": [ "User.Read" ] 22 | } 23 | ], 24 | "ManualSteps": [ 25 | { "Comment": "click Settings > Required permissions > Grant Permissions" } 26 | ] 27 | } 28 | ], 29 | 30 | /* 31 | This section describes the users that need to be created to test the sample (if any) with their roles and groups 32 | */ 33 | "Users": [ 34 | /* 35 | { 36 | "Alias": "user1" 37 | } 38 | */ 39 | ], 40 | 41 | 42 | /* 43 | This section describes how to update (the code in configuration files) from the apps coordinates 44 | Each section describes a configuration file, for one of the apps, it's type (XML, JSon, plain text), its location 45 | with respect to the root of the sample, and the mappping (which string in the config file is mapped to which value 46 | */ 47 | "CodeConfiguration": [ 48 | { 49 | "App": "app", 50 | "SettingKind": "Text", 51 | "SettingFile": "\\..\\src\\main\\java\\PublicClient.java", 52 | "Mappings": [ 53 | { 54 | "key": "private final static String APP_ID", 55 | "value": "app.AppId" 56 | } 57 | ] 58 | } 59 | ] 60 | } 61 | -------------------------------------------------------------------------------- /Username-Password-Flow/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | services: active-directory 3 | platforms: Java 4 | endpoint: Microsoft identity platform 5 | page_type: sample 6 | languages: 7 | - Java 8 | author: ramya25 9 | products: 10 | - azure 11 | - azure-active-directory 12 | - Java 13 | - office-ms-graph 14 | description: "Java console application letting users sign-in with their username/password and call Microsoft Graph API" 15 | urlFragment: call-msgraph-with-username-password 16 | --- 17 | 18 | # Java console application letting users sign-in with username/password and call Microsoft Graph API 19 | 20 | ## About this sample 21 | 22 | ### Overview 23 | 24 | This sample demonstrates how to use Microsoft Authentication Library for Java to: 25 | 26 | - Authenticate the user silently using username and password. 27 | - Call to a web API (in this case, the [Microsoft Graph](https://graph.microsoft.com)) 28 | 29 | ![Topology](./ReadmeFiles/Java-Native-Diagram.png) 30 | 31 | ### Scenario 32 | 33 | The application obtains a token through username and password, and then calls the Microsoft Graph to get information about the signed-in user. 34 | 35 | Note that Username/Password is needed in some cases (for instance devops scenarios) but it's not recommended because: 36 | 37 | - This requires having credentials in the application, which does not happen with the other flows. 38 | - The credentials should only be used when there is a high degree of trust between the resource owner and the client and when other authorization grant types are not available (such as an authorization code). 39 | - Do note that this attempts to authenticate and obtain tokens for users using this flow will often fail with applications registered with Azure AD. Some of the situations and scenarios that will cause the failure are listed below 40 | - When the user needs to consent to permissions that this application is requesting. 41 | - When a conditional access policy enforcing multi-factor authentication is in force. 42 | - Azure AD Identity Protection can block authentication attempts if this user account is compromised. 43 | - The user's password is expired and requires a reset. 44 | 45 | While this flow seems simpler than the others, applications using these flows often encounter more problems as compared to other flows. 46 | 47 | The modern authentication protocols (SAML, WS-Fed, OAuth and OpenID), in principal, discourage apps from handling user credentials themselves. The aim is to decouple the authentication method from an app. Azure AD controls the login experience to avoid exposing secrets (like passwords) to a website or an app. 48 | 49 | This enables IdPs like Azure AD to provide seamless single sign-on experiences, enable users to authenticate using factors other than passwords (phone, face, biometrics) and Azure AD can block or elevate authentication attempts if it discerns that the user’s account is compromised or the user is trying to access an app from an untrusted location and such. 50 | 51 | ## How to run this sample 52 | 53 | To run this sample, you'll need: 54 | 55 | - Working installation of Java and Maven. 56 | - An Internet connection. 57 | - An Azure Active Directory (Azure AD) tenant. For more information on how to get an Azure AD tenant, see [How to get an Azure AD tenant](https://azure.microsoft.com/en-us/documentation/articles/active-directory-howto-tenant/). 58 | - A user account in your Azure AD tenant. This sample will not work with a Microsoft account (formerly Windows Live account). Therefore, if you signed in to the [Azure portal](https://portal.azure.com) with a Microsoft account and have never created a user account in your directory before, you need to do that now. 59 | 60 | ## Quick Start 61 | 62 | Getting started with the sample is easy. It is configured to run out of the box with minimal setup. 63 | 64 | ### Step 1: Download Java (8 and above) for your platform 65 | 66 | To successfully use this sample, you need a working installation of [Java](http://www.oracle.com/technetwork/java/javase/downloads/index.html) and [Maven](https://maven.apache.org/). 67 | 68 | ### Step 2: Clone or download this repository 69 | 70 | From your shell or command line: 71 | 72 | ```Shell 73 | git clone https://github.com/Azure-Samples/ms-identity-java-desktop.git 74 | cd "Username-Password-Flow" 75 | ``` 76 | 77 | ### Step 3: Register the sample with your Azure Active Directory tenant 78 | 79 | To register the project, you can: 80 | 81 | - either follow the steps in the paragraphs below 82 | - or use PowerShell scripts that: 83 | - **automatically** create for you the Azure AD applications and related objects (passwords, permissions, dependencies) 84 | - modify the projects' configuration files. 85 | 86 | If you want to use this automation, read the instructions in [App Creation Scripts](./AppCreationScripts/AppCreationScripts.md) 87 | 88 | ### First step: choose the Azure AD tenant where you want to create your applications 89 | 90 | As a first step you'll need to: 91 | 92 | 1. Sign in to the [Azure portal](https://portal.azure.com) using either a work or school account or a personal Microsoft account. 93 | 1. If your account is present in more than one Azure AD tenant, select your profile at the top right corner in the menu on top of the page, and then **switch directory**. 94 | Change your portal session to the desired Azure AD tenant. 95 | 1. In the portal menu, click on **All services**, and choose **Azure Active Directory**. 96 | 97 | > In the next steps, you might need the tenant name (or directory name) or the tenant ID (or directory ID). These are presented in the **Properties** of the Azure Active Directory window respectively as *Name* and *Directory ID* 98 | 99 | #### Register the app app (Java-Console-Application) 100 | 101 | 1. Navigate to the Microsoft identity platform for developers [App registrations](https://go.microsoft.com/fwlink/?linkid=2083908) page. 102 | 1. Click **New registration**. 103 | 1. When the **Register an application page** appears, enter your application's registration information: 104 | - In the **Name** section, enter a meaningful application name that will be displayed to users of the app, for example `Java-Console-Application`. 105 | - In the **Supported account types** section, select **Accounts in any organizational directory**. 106 | 1. Select **Register** to create the application. 107 | 1. In the app's registration **Overview** page, find the **Application (client) ID** value and record it for later. You'll need it to configure the APP_ID value in `UsernamePasswordFlow.Java` later. 108 | 1. In the Application menu blade, select **Manifest**, and: 109 | - In the manifest editor, set the `allowPublicClient` property to **true** 110 | - Select **Save** in the bar above the manifest editor. 111 | 1. In the Application menu blade, select **API permissions** 112 | - Ensure that the **User.Read** permission is listed in the permissions list (which is automatically added when you register your application). 113 | 114 | 1. At this stage permissions are assigned correctly but the client app does not allow interaction. 115 | Therefore no consent can be presented via UI and accepted to use the service app. 116 | Click the **Grant/revoke admin consent for {tenant}** button, and then select **Yes** when you are asked if you want to grant consent for the requested permissions for all accounts in the tenant. 117 | You need to be an Azure AD tenant admin to do this. 118 | 119 | ### Step 4: Configure the sample to use your Azure AD tenant 120 | 121 | In the steps below, ClientID is the same as Application ID or AppId. 122 | 123 | #### Configure the app project 124 | 125 | 1. Open the `src\main\resources\application.properties` file 126 | 1. Set the `CLIENT_ID` property to the client ID value you recorded earlier 127 | 1. Set the `USER_NAME` and `USER_PASSWORD` properties to the username and password of the user you wish to authenticate in this sample 128 | 129 | ### Step 5: Run the sample 130 | 131 | From your shell or command line: 132 | 133 | - `$ mvn clean compile assembly:single` 134 | 135 | This will generate a `public-client-msal4j-sample-jar-with-dependencies.jar` file in your /targets directory. Run this using your Java executable like below: 136 | 137 | - `$ java -jar public-client-msal4j-sample-jar-with-dependencies.jar` 138 | 139 | ### You're done 140 | 141 | Simply run the .jar file as described in step 5 or run the main method of `UsernamePasswordFlow.java` in your IDE to watch the sample acquire a token for the user you configured. 142 | 143 | ### About the code 144 | 145 | The code to acquire a token is located entirely in `src\main\java\UsernamePasswordFlow.Java`. The public client application is created using the **MSAL build pattern**, by passing the Application ID, an authority, and an implementation of the token cache interface. 146 | 147 | ```java 148 | PublicClientApplication pca = PublicClientApplication.builder(clientId) 149 | .authority(authority) 150 | .setTokenCacheAccessAspect(tokenCacheAspect) 151 | .build(); 152 | ``` 153 | 154 | A call to acquire the token is first made using the public client application, by creating a `SilentParameters` object to send to the application's `acquireTokenSilently()` method. The `SilentParameters` builder takes in an account (taken from the token cache) and a set of scopes. `acquireTokenSilently()` retrieves that account's token from the cache if one exists and isn't expired. If the token is expired, an attempt to retireve a new token is made if the cache contains a refresh token. 155 | 156 | If there is no token in the cache for the given account or some issue occurs when trying to use a refresh token, the code falls back to the username/password flow described below 157 | 158 | ```java 159 | SilentParameters silentParameters = 160 | SilentParameters 161 | .builder(scope) 162 | .account(account) 163 | .build(); 164 | 165 | result = pca.acquireTokenSilently(silentParameters).join(); 166 | 167 | ``` 168 | 169 | A call to acquire the token is first made using the public client application, by creating a `UserNamePasswordParameters` object to send to the application's `acquireToken()` method. The `UserNamePasswordParameters` builder takes in the username and password of a user, and a set of scopes. `acquireToken()` attempts to acquires a token from the authority configured in the application via the username/password authentication. 170 | 171 | ```java 172 | UserNamePasswordParameters parameters = 173 | UserNamePasswordParameters 174 | .builder(scope, username, password.toCharArray()) 175 | .build(); 176 | 177 | result = pca.acquireToken(parameters).join(); 178 | ``` 179 | 180 | ## Community Help and Support 181 | 182 | Use [Stack Overflow](http://stackoverflow.com/questions/tagged/msal) to get support from the community. 183 | Ask your questions on Stack Overflow first and browse existing issues to see if someone has asked your question before. 184 | Make sure that your questions or comments are tagged with [`msal` `Java`]. 185 | 186 | If you find a bug in the sample, please raise the issue on [GitHub Issues](https://github.com/Azure-Samples/ms-identity-java-desktop/issues). 187 | 188 | To provide a recommendation, visit the following [User Voice page](https://feedback.azure.com/forums/169401-azure-active-directory). 189 | 190 | ## Contributing 191 | 192 | If you'd like to contribute to this sample, see CONTRIBUTING.md 193 | 194 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information, see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 195 | 196 | ## More information 197 | 198 | For more information, see MSAL4J [conceptual documentation](https://github.com/AzureAD/microsoft-authentication-library-for-java/wiki). 199 | 200 | - [Quickstart: Configure a client application to access web APIs](https://docs.microsoft.com/azure/active-directory/develop/quickstart-configure-app-access-web-apis) 201 | - [Understanding Azure AD application consent experiences](https://docs.microsoft.com/azure/active-directory/develop/application-consent-experience) 202 | - [Understand user and admin consent](https://docs.microsoft.com/azure/active-directory/develop/howto-convert-app-to-be-multi-tenant#understand-user-and-admin-consent) 203 | - About how OAuth 2.0 protocols work in this scenario and other scenarios, see [Authentication Scenarios for Azure AD](http://go.microsoft.com/fwlink/?LinkId=394414). 204 | 205 | For more information about how OAuth 2.0 protocols work in this scenario and other scenarios, see [Authentication Scenarios for Azure AD](http://go.microsoft.com/fwlink/?LinkId=394414). 206 | -------------------------------------------------------------------------------- /Username-Password-Flow/ReadmeFiles/Java-Native-Diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/ms-identity-java-desktop/da27a1af6064d5e833e645e5040a5120a0c2698f/Username-Password-Flow/ReadmeFiles/Java-Native-Diagram.png -------------------------------------------------------------------------------- /Username-Password-Flow/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.microsoft.azure 5 | public-client-username-password-sample 6 | jar 7 | 1.0.0 8 | public-client-username-password-sample 9 | 10 | 11 | 12 | com.microsoft.azure 13 | msal4j 14 | 1.10.1 15 | 16 | 17 | org.slf4j 18 | slf4j-simple 19 | 1.7.29 20 | 21 | 22 | 23 | 24 | 25 | 26 | org.apache.maven.plugins 27 | maven-compiler-plugin 28 | 3.8.1 29 | 30 | 8 31 | 8 32 | 33 | 34 | 35 | maven-assembly-plugin 36 | 37 | 38 | package 39 | 40 | single 41 | 42 | 43 | 44 | 45 | 46 | 47 | UsernamePasswordFlow 48 | 49 | 50 | 51 | jar-with-dependencies 52 | 53 | false 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /Username-Password-Flow/src/main/java/UsernamePasswordFlow.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | import com.microsoft.aad.msal4j.IAccount; 5 | import com.microsoft.aad.msal4j.IAuthenticationResult; 6 | import com.microsoft.aad.msal4j.MsalException; 7 | import com.microsoft.aad.msal4j.PublicClientApplication; 8 | import com.microsoft.aad.msal4j.SilentParameters; 9 | import com.microsoft.aad.msal4j.UserNamePasswordParameters; 10 | 11 | import java.io.IOException; 12 | import java.util.Collections; 13 | import java.util.Properties; 14 | import java.util.Set; 15 | 16 | public class UsernamePasswordFlow { 17 | 18 | private static String authority; 19 | private static Set scope; 20 | private static String clientId; 21 | private static String username; 22 | private static String password; 23 | 24 | public static void main(String args[]) throws Exception { 25 | 26 | setUpSampleData(); 27 | 28 | PublicClientApplication pca = PublicClientApplication.builder(clientId) 29 | .authority(authority) 30 | .build(); 31 | 32 | //Get list of accounts from the application's token cache, and search them for the configured username 33 | //getAccounts() will be empty on this first call, as accounts are added to the cache when acquiring a token 34 | Set accountsInCache = pca.getAccounts().join(); 35 | IAccount account = getAccountByUsername(accountsInCache, username); 36 | 37 | //Attempt to acquire token when user's account is not in the application's token cache 38 | IAuthenticationResult result = acquireTokenUsernamePassword(pca, scope, account, username, password); 39 | System.out.println("Account username: " + result.account().username()); 40 | System.out.println("Access token: " + result.accessToken()); 41 | System.out.println("Id token: " + result.idToken()); 42 | System.out.println(); 43 | 44 | accountsInCache = pca.getAccounts().join(); 45 | account = getAccountByUsername(accountsInCache, username); 46 | 47 | //Attempt to acquire token again, now that the user's account and a token are in the application's token cache 48 | result = acquireTokenUsernamePassword(pca, scope, account, username, password); 49 | System.out.println("Account username: " + result.account().username()); 50 | System.out.println("Access token: " + result.accessToken()); 51 | System.out.println("Id token: " + result.idToken()); 52 | } 53 | 54 | private static IAuthenticationResult acquireTokenUsernamePassword(PublicClientApplication pca, 55 | Set scope, 56 | IAccount account, 57 | String username, 58 | String password) throws Exception { 59 | IAuthenticationResult result; 60 | try { 61 | SilentParameters silentParameters = 62 | SilentParameters 63 | .builder(scope) 64 | .account(account) 65 | .build(); 66 | // Try to acquire token silently. This will fail on the first acquireTokenUsernamePassword() call 67 | // because the token cache does not have any data for the user you are trying to acquire a token for 68 | result = pca.acquireTokenSilently(silentParameters).join(); 69 | System.out.println("==acquireTokenSilently call succeeded"); 70 | } catch (Exception ex) { 71 | if (ex.getCause() instanceof MsalException) { 72 | System.out.println("==acquireTokenSilently call failed: " + ex.getCause()); 73 | UserNamePasswordParameters parameters = 74 | UserNamePasswordParameters 75 | .builder(scope, username, password.toCharArray()) 76 | .build(); 77 | // Try to acquire a token via username/password. If successful, you should see 78 | // the token and account information printed out to console 79 | result = pca.acquireToken(parameters).join(); 80 | System.out.println("==username/password flow succeeded"); 81 | } else { 82 | // Handle other exceptions accordingly 83 | throw ex; 84 | } 85 | } 86 | return result; 87 | } 88 | 89 | /** 90 | * Helper function to return an account from a given set of accounts based on the given username, 91 | * or return null if no accounts in the set match 92 | */ 93 | private static IAccount getAccountByUsername(Set accounts, String username) { 94 | if (accounts.isEmpty()) { 95 | System.out.println("==No accounts in cache"); 96 | } else { 97 | System.out.println("==Accounts in cache: " + accounts.size()); 98 | for (IAccount account : accounts) { 99 | if (account.username().equals(username)) { 100 | return account; 101 | } 102 | } 103 | } 104 | return null; 105 | } 106 | 107 | /** 108 | * Helper function unique to this sample setting. In a real application these wouldn't be so hardcoded, for example 109 | * values such as username/password would come from the user, and different users may require different scopes 110 | */ 111 | private static void setUpSampleData() throws IOException { 112 | // Load properties file and set properties used throughout the sample 113 | Properties properties = new Properties(); 114 | properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("application.properties")); 115 | authority = properties.getProperty("AUTHORITY"); 116 | scope = Collections.singleton(properties.getProperty("SCOPE")); 117 | clientId = properties.getProperty("CLIENT_ID"); 118 | username = properties.getProperty("USER_NAME"); 119 | password = properties.getProperty("USER_PASSWORD"); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Username-Password-Flow/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | CLIENT_ID= 2 | USER_NAME= 3 | USER_PASSWORD= 4 | 5 | # The below properties do not need to be changed for this sample 6 | # In a real situation they would be used to affect authentication behavior, such as changing where token requests are 7 | # sent by using a different authority URL 8 | AUTHORITY=https://login.microsoftonline.com/organizations/ 9 | SCOPE=user.read --------------------------------------------------------------------------------