Skip to content

Commit d0aee67

Browse files
authored
Merge pull request #87081 from jmprieur/java
Update to the Web app scenario to include Java
2 parents c724a14 + 121ae46 commit d0aee67

6 files changed

+446
-97
lines changed

articles/active-directory/develop/quickstart-v2-java-webapp.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,11 @@ When you've completed the guide, your application will accept sign-ins of person
3030

3131
![Shows how the sample app generated by this quickstart works](media/quickstart-v2-java-webapp/java-quickstart.svg)
3232

33-
> ## Prerequisites
34-
> To run this sample you will need:
35-
> - Java Development Kit (JDK) 8 or greater and Maven.
36-
>
33+
## Prerequisites
34+
35+
To run this sample you will need:
36+
- Java Development Kit (JDK) 8 or greater and Maven.
37+
3738
> [!div renderon="docs"]
3839
> ## Register and download your quickstart app
3940
> You have two options to start your quickstart application: express (Option 1), or manual (Option 2)

articles/active-directory/develop/scenario-web-app-sign-user-app-configuration.md

Lines changed: 226 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ ms.devlang: na
1212
ms.topic: conceptual
1313
ms.tgt_pltfrm: na
1414
ms.workload: identity
15-
ms.date: 05/07/2019
15+
ms.date: 09/17/2019
1616
ms.author: jmprieur
1717
ms.custom: aaddev
1818
#Customer intent: As an application developer, I want to know how to write a Web app that signs-in users using the Microsoft identity platform for developers.
@@ -31,20 +31,33 @@ The libraries used to protect a Web App (and a Web API) are:
3131
| Platform | Library | Description |
3232
|----------|---------|-------------|
3333
| ![.NET](media/sample-v2-code/logo_net.png) | [Identity model extensions for .NET](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/wiki) | Used directly by ASP.NET and ASP.NET Core, Microsoft Identity Extensions for .NET proposes a set of DLLs running both on .NET Framework and .NET Core. From an ASP.NET/ASP.NET Core Web app, you can control token validation using the **TokenValidationParameters** class (in particular in some ISV scenarios) |
34+
| ![Java](media/sample-v2-code/logo_java.png) | [msal4j](https://github.com/AzureAD/microsoft-authentication-library-for-java/wiki) | MSAL for Java - currently in public preview |
35+
| ![Python](media/sample-v2-code/logo_python.png) | [MSAL Python](https://github.com/AzureAD/microsoft-authentication-library-for-python/wiki) | MSAL for Python - currently in public preview |
3436

35-
## ASP.NET Core configuration
37+
Code snippets in this article and the following are extracted from:
3638

37-
Code snippets in this article and the following are extracted from the [ASP.NET Core Web app incremental tutorial, chapter 1](https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/1-WebApp-OIDC/1-1-MyOrg). You might want to refer to that tutorial for full implementation details.
39+
- the [ASP.NET Core Web app incremental tutorial, chapter 1](https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/1-WebApp-OIDC/1-1-MyOrg).
40+
- the [ASP.NET Web app sample](https://github.com/Azure-Samples/ms-identity-aspnet-webapp-openidconnect)
41+
- the [Java web application calling Microsoft graph](https://github.com/Azure-Samples/ms-identity-java-webapp) msal4j web app sample
42+
- the [Python web application calling Microsoft graph](https://github.com/Azure-Samples/ms-identity-python-webapp) MSAL.Python web app sample
3843

39-
### Application configuration files
44+
You might want to refer to these tutorials and sample for full implementation details.
4045

41-
In ASP.NET Core, a Web application signing-in users with the Microsoft identity platform is configured through the `appsettings.json` file. The settings that you need to fill in are:
46+
## Configuration files
4247

43-
- the cloud `Instance` if you want your app to run in national clouds
48+
Web applications that sign in users with the Microsoft identity platform are usually configured through configuration files. The settings that you need to fill in are:
49+
50+
- the cloud `Instance` if you want your app to run (for instance in national clouds)
4451
- the audience in `tenantId`
4552
- the `clientId` for your application, as copied from the Azure portal.
4653

47-
```JSon
54+
Sometimes, applications can be parametrized by the `authority`, which is the concatenation of the `instance` and the `tenantId`
55+
56+
# [ASP.NET Core](#tab/aspnetcore)
57+
58+
In ASP.NET Core, these settings are located in the `appsettings.json` file, in the "AzureAD" section.
59+
60+
```Json
4861
{
4962
"AzureAd": {
5063
// Azure Cloud instance among:
@@ -69,9 +82,9 @@ In ASP.NET Core, a Web application signing-in users with the Microsoft identity
6982
}
7083
```
7184

72-
In ASP.NET Core, there's another file that contains the URL (`applicationUrl`) and the SSL Port (`sslPort`) for your application as well as various profiles.
85+
In ASP.NET Core, there's another file (`properties\launchSettings.json`) that contains the URL (`applicationUrl`) and the SSL Port (`sslPort`) for your application and various profiles.
7386

74-
```JSon
87+
```Json
7588
{
7689
"iisSettings": {
7790
"windowsAuthentication": false,
@@ -103,42 +116,9 @@ In ASP.NET Core, there's another file that contains the URL (`applicationUrl`) a
103116

104117
In the Azure portal, the reply URIs that you need to register in the **Authentication** page for your application needs to match these URLs; that is, for the two configuration files above, they would be `https://localhost:44321/signin-oidc` as the applicationUrl is `http://localhost:3110` but the `sslPort` is specified (44321), and the `CallbackPath` is `/signin-oidc` as defined in the `appsettings.json`.
105118

106-
In the same way, the sign out URI would be set to `https://localhost:44321/signout-callback-oidc`.
107-
108-
### Initialization code
109-
110-
In ASP.NET Core Web Apps (and Web APIs), the code doing the application initialization is located in the `Startup.cs` file, and, to add authentication with the Microsoft identity platform (formerly Azure AD v2.0), you'll need to add the following code. The comments in the code should be self-explanatory.
111-
112-
> [!NOTE]
113-
> If you start your project with default ASP.NET core web project within Visual studio or using `dotnet new mvc` the method `AddAzureAD` is available by default because the related packages are automatically loaded.
114-
> However if you build a project from scratch and are trying to use the below code we suggest you to add the NuGet Package **"Microsoft.AspNetCore.Authentication.AzureAD.UI"** to your project to make the `AddAzureAD` method available.
115-
116-
```CSharp
117-
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
118-
.AddAzureAD(options => configuration.Bind("AzureAd", options));
119+
In the same way, the sign-out URI would be set to `https://localhost:44321/signout-callback-oidc`.
119120

120-
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
121-
{
122-
// The ASP.NET core templates are currently using Azure AD v1.0, and compute
123-
// the authority (as {Instance}/{TenantID}). We want to use the Microsoft identity platform endpoint
124-
options.Authority = options.Authority + "/v2.0/";
125-
126-
// If you want to restrict the users that can sign-in to specific organizations
127-
// Set the tenant value in the appsettings.json file to 'organizations', and add the
128-
// issuers you want to accept to options.TokenValidationParameters.ValidIssuers collection.
129-
// Otherwise validate the issuer
130-
options.TokenValidationParameters.IssuerValidator = AadIssuerValidator.ForAadInstance(options.Authority).ValidateAadIssuer;
131-
132-
// Set the nameClaimType to be preferred_username.
133-
// This change is needed because certain token claims from Azure AD v1.0 endpoint
134-
// (on which the original .NET core template is based) are different in Microsoft identity platform endpoint.
135-
// For more details see [ID Tokens](https://docs.microsoft.com/azure/active-directory/develop/id-tokens)
136-
// and [Access Tokens](https://docs.microsoft.com/azure/active-directory/develop/access-tokens)
137-
options.TokenValidationParameters.NameClaimType = "preferred_username";
138-
...
139-
```
140-
141-
## ASP.NET configuration
121+
# [ASP.NET](#tab/aspnet)
142122

143123
In ASP.NET, the application is configured through the `Web.Config` file
144124

@@ -162,6 +142,149 @@ In ASP.NET, the application is configured through the `Web.Config` file
162142
</appSettings>
163143
```
164144

145+
In the Azure portal, the reply URIs that you need to register in the **Authentication** page for your application needs to match these URLs; that is `https://localhost:44326/`.
146+
147+
# [Java](#tab/java)
148+
149+
In Java, the configuration is located in the `application.properties` file located under `src/main/resources`
150+
151+
```Java
152+
aad.clientId=Enter_the_Application_Id_here
153+
aad.authority=https://login.microsoftonline.com/Enter_the_Tenant_Info_Here/
154+
aad.secretKey=Enter_the_Client_Secret_Here
155+
aad.redirectUriSignin=http://localhost:8080/msal4jsample/secure/aad
156+
aad.redirectUriGraphUsers=http://localhost:8080/msal4jsample/graph/users
157+
```
158+
159+
In the Azure portal, the reply URIs that you need to register in the **Authentication** page for your application needs to match the redirectUris defined by the application, that is `http://localhost:8080/msal4jsample/secure/aad` and `http://localhost:8080/msal4jsample/graph/users`
160+
161+
# [Python](#tab/python)
162+
163+
Here is the Python configuration file in [app_config.py](https://github.com/Azure-Samples/ms-identity-python-webapp/blob/web_app_sample/app_config.py)
164+
165+
```Python
166+
AUTHORITY = "https://login.microsoftonline.com/Enter_the_Tenant_Name_Here"
167+
CLIENT_ID = "Enter_the_Application_Id_here"
168+
CLIENT_SECRET = "Enter_the_Client_Secret_Here"
169+
SCOPE = ["https://graph.microsoft.com/User.Read"]
170+
REDIRECT_URI = "http://localhost:5000/getAToken"
171+
```
172+
173+
---
174+
175+
## Initialization code
176+
177+
The initialization code is different depending on the platform. For ASP.NET Core and ASP.NET, signing in users is delegated to the OpenIDConnect middleware. Today the ASP.NET / ASP.NET Core template generate web applications for the Azure AD v1.0 endpoint. Therefore, a bit of configuration is required to adapt them to the Microsoft identity platform (v2.0) endpoint. In the case of Java, it's handled by Spring with the cooperation of the application.
178+
179+
# [ASP.NET Core](#tab/aspnetcore)
180+
181+
In ASP.NET Core Web Apps (and Web APIs), the application is protected because you have a `[Authorize]` attribute on the controllers or the controller actions. This attribute checks that the user is authenticated. The code doing the application initialization is located in the `Startup.cs` file, and, to add authentication with the Microsoft identity platform (formerly Azure AD v2.0), you'll need to add the following code. The comments in the code should be self-explanatory.
182+
183+
> [!NOTE]
184+
> If you start your project with default ASP.NET core web project within Visual studio or using `dotnet new mvc` the method `AddAzureAD` is available by default because the related packages are automatically loaded.
185+
> However if you build a project from scratch and are trying to use the below code we suggest you to add the NuGet Package **"Microsoft.AspNetCore.Authentication.AzureAD.UI"** to your project to make the `AddAzureAD` method available.
186+
187+
The following code is available from [Startup.cs#L33-L34](https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/blob/faa94fd49c2da46b22d6694c4f5c5895795af26d/1-WebApp-OIDC/1-1-MyOrg/Startup.cs#L33-L34)
188+
189+
```CSharp
190+
public class Startup
191+
{
192+
...
193+
194+
// This method gets called by the runtime. Use this method to add services to the container.
195+
public void ConfigureServices(IServiceCollection services)
196+
{
197+
...
198+
// Sign-in users with the Microsoft identity platform
199+
services.AddMicrosoftIdentityPlatformAuthentication(Configuration);
200+
201+
services.AddMvc(options =>
202+
{
203+
var policy = new AuthorizationPolicyBuilder()
204+
.RequireAuthenticatedUser()
205+
.Build();
206+
options.Filters.Add(new AuthorizeFilter(policy));
207+
})
208+
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
209+
}
210+
```
211+
212+
The `AddMicrosoftIdentityPlatformAuthentication` is an extension method defined in [Microsoft.Identity.Web/WebAppServiceCollectionExtensions.cs#L23](https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/blob/faa94fd49c2da46b22d6694c4f5c5895795af26d/Microsoft.Identity.Web/WebAppServiceCollectionExtensions.cs#L23). It:
213+
214+
- adds the authentication service
215+
- configure options to read the config file
216+
- configures the OpenID connect options so that the used authority is the Microsoft identity platform (formerly Azure AD v2.0) endpoint
217+
- the issuer of the token is validated
218+
- the claims corresponding to name is mapped from the "preferred_username" claim in the ID Token
219+
220+
In addition to the configuration, you can specify, when calling `AddMicrosoftIdentityPlatformAuthentication`:
221+
222+
- the name of the configuration section (by default AzureAD)
223+
- if you want to trace the OpenIdConnect middleware events, which can help you troubleshooting your Web application if authentication doesn't work: setting `subscribeToOpenIdConnectMiddlewareDiagnosticsEvents` to `true` will show you how information gets elaborated by the set of ASP.NET Core middleware as it progresses from the HTTP response to the identity of the user in the `HttpContext.User`.
224+
225+
```CSharp
226+
/// <summary>
227+
/// Add authentication with Microsoft identity platform.
228+
/// This method expects the configuration file will have a section named "AzureAd" with the necessary settings to initialize authentication options.
229+
/// </summary>
230+
/// <param name="services">Service collection to which to add this authentication scheme</param>
231+
/// <param name="configuration">The Configuration object</param>
232+
/// <param name="subscribeToOpenIdConnectMiddlewareDiagnosticsEvents">
233+
/// Set to true if you want to debug, or just understand the OpenIdConnect events.
234+
/// </param>
235+
/// <returns></returns>
236+
public static IServiceCollection AddMicrosoftIdentityPlatformAuthentication(
237+
this IServiceCollection services,
238+
IConfiguration configuration,
239+
string configSectionName = "AzureAd",
240+
bool subscribeToOpenIdConnectMiddlewareDiagnosticsEvents = false)
241+
{
242+
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
243+
.AddAzureAD(options => configuration.Bind(configSectionName, options));
244+
services.Configure<AzureADOptions>(options => configuration.Bind(configSectionName, options));
245+
246+
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
247+
{
248+
// Per the code below, this application signs in users in any Work and School
249+
// accounts and any Microsoft Personal Accounts.
250+
// If you want to direct Azure AD to restrict the users that can sign-in, change
251+
// the tenant value of the appsettings.json file in the following way:
252+
// - only Work and School accounts => 'organizations'
253+
// - only Microsoft Personal accounts => 'consumers'
254+
// - Work and School and Personal accounts => 'common'
255+
// If you want to restrict the users that can sign-in to only one tenant
256+
// set the tenant value in the appsettings.json file to the tenant ID
257+
// or domain of this organization
258+
options.Authority = options.Authority + "/v2.0/";
259+
260+
// If you want to restrict the users that can sign-in to several organizations
261+
// Set the tenant value in the appsettings.json file to 'organizations', and add the
262+
// issuers you want to accept to options.TokenValidationParameters.ValidIssuers collection
263+
options.TokenValidationParameters.IssuerValidator = AadIssuerValidator.GetIssuerValidator(options.Authority).Validate;
264+
265+
// Set the nameClaimType to be preferred_username.
266+
// This change is needed because certain token claims from Azure AD V1 endpoint
267+
// (on which the original .NET core template is based) are different than Microsoft identity platform endpoint.
268+
// For more details see [ID Tokens](https://docs.microsoft.com/azure/active-directory/develop/id-tokens)
269+
// and [Access Tokens](https://docs.microsoft.com/azure/active-directory/develop/access-tokens)
270+
options.TokenValidationParameters.NameClaimType = "preferred_username";
271+
272+
// ...
273+
274+
if (subscribeToOpenIdConnectMiddlewareDiagnosticsEvents)
275+
{
276+
OpenIdConnectMiddlewareDiagnostics.Subscribe(options.Events);
277+
}
278+
});
279+
return services;
280+
}
281+
...
282+
```
283+
284+
The `AadIssuerValidator` class enables that the issuer of the token is validated in many cases (v1.0 or v2.0 token, single-tenant, or multi-tenant application or application that signs in users with their personal Microsoft accounts, in the Azure public cloud or national clouds). It's available from [Microsoft.Identity.Web/Resource/AadIssuerValidator.cs](https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/blob/master/Microsoft.Identity.Web/Resource/AadIssuerValidator.cs)
285+
286+
# [ASP.NET](#tab/aspnet)
287+
165288
The code related to authentication in ASP.NET Web app / Web APIs is located in the `App_Start/Startup.Auth.cs` file.
166289

167290
```CSharp
@@ -186,7 +309,66 @@ The code related to authentication in ASP.NET Web app / Web APIs is located in t
186309
}
187310
```
188311

312+
# [Java](#tab/java)
313+
314+
The Java sample uses the Spring framework. The application is protected because you implement a `Filter`, which gets each HTTP response. In the Java Web app quickstart, this is `AuthFilter` in `src/main/java/com/microsoft/azure/msalwebsample/AuthFilter.java`. The filter process the OAuth 2.0 authorization code flow and therefore:
315+
316+
- verifies if the user is authenticated (`isAuthenticated()` method)
317+
- if the user isn't authenticated, it computes the url of the Azure AD authorize endpoints, and redirects the browser to this URI
318+
- when the response arrives, containing the auth code flow it lets's msal4j acquiring the token.
319+
- when it finally receives the token from the token endpoint (on the redirect URI), the user is signed in.
320+
321+
For details see the `doFilter()` method in [AuthFilter.java](https://github.com/Azure-Samples/ms-identity-java-webapp/blob/master/src/main/java/com/microsoft/azure/msalwebsample/AuthFilter.java)
322+
323+
> [!NOTE]
324+
> The code of the `doFilter()` is written in a slightly different order, but the flow is the one described.
325+
326+
See [Microsoft identity platform and OAuth 2.0 authorization code flow](v2-oauth2-auth-code-flow.md) for details about the authorization code flow triggered by this method
327+
328+
# [Python](#tab/python)
329+
330+
The Python sample uses Flask. The initialization of flask, and MSAL.Python is done in [app.py#L1-L17](https://github.com/Azure-Samples/ms-identity-python-webapp/blob/e1199b4c3cdcb637cf0d8306832efbd85492e123/app.py#L1-L17)
331+
332+
```Python
333+
import uuid
334+
import flask
335+
import requests
336+
from flask import Flask, render_template, session, request
337+
from flask_session import Session
338+
import msal
339+
import app_config
340+
341+
sess = Session()
342+
app = Flask(__name__)
343+
app.config.from_object('config.Config')
344+
sess.init_app(app)
345+
cache = msal.SerializableTokenCache()
346+
application = msal.ConfidentialClientApplication(
347+
app_config.CLIENT_ID, authority=app_config.AUTHORITY,
348+
client_credential=app_config.CLIENT_SECRET,
349+
token_cache=cache)
350+
```
351+
352+
This is MSAL.Python that will take care of letting the user sign-in. See [app.py#L74-84](https://github.com/Azure-Samples/ms-identity-python-webapp/blob/e1199b4c3cdcb637cf0d8306832efbd85492e123/app.py#L74-84)
353+
354+
```Python
355+
@app.route('/authenticate')
356+
def authenticate():
357+
# Call to the authorize endpoint
358+
auth_state = str(uuid.uuid4())
359+
session[(request.cookies.get("session")+'state')] = auth_state
360+
authorization_url = application.get_authorization_request_url(app_config.SCOPE, state=auth_state,
361+
redirect_uri=app_config.REDIRECT_URI)
362+
resp = flask.Response(status=307)
363+
resp.headers['location'] = authorization_url
364+
return resp
365+
```
366+
367+
---
368+
189369
## Next steps
190370

371+
In the next article, you'll learn how to trigger the sign-in and sign-out.
372+
191373
> [!div class="nextstepaction"]
192374
> [Sign in and sign out](scenario-web-app-sign-user-sign-in.md)

0 commit comments

Comments
 (0)