Skip to content
This repository was archived by the owner on Jun 12, 2026. It is now read-only.

protect-web-api: client and api - #12

Open
idg-sam wants to merge 13 commits into
tutorial-formatfrom
protect-web-api
Open

protect-web-api: client and api#12
idg-sam wants to merge 13 commits into
tutorial-formatfrom
protect-web-api

Conversation

@idg-sam

@idg-sam idg-sam commented Jun 28, 2021

Copy link
Copy Markdown
Contributor

No description provided.

description: "This sample demonstrates a Java Spring web application calling a Java Spring web API that is secured using Azure AD"
azureDeploy: <ENTER_FULLY_QUALIFIED_URL_TO_AN_AZURE_RESOURCE_MANAGER>
extendedZipContent: <FILES_OR_FOLDERS_WITH_TWO_ABSOLUTE_PATHS_TO_INCLUDE_WITH_ZIP:PATH(NAME_IN_THE_REPO), TARGET(NAME_IN_THE_ZIP)>
extensions: <ENTER_CONTENT_THAT_OTHER_TEAMS_CAN_USE_TO_IDENTIFY_SAMPLES>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
extensions: <ENTER_CONTENT_THAT_OTHER_TEAMS_CAN_USE_TO_IDENTIFY_SAMPLES>
extensions: <ENTER_CONTENT_THAT_OTHER_TEAMS_CAN_USE_TO_IDENTIFY_SAMPLES>

Reminder to remove these

- [More information](#more-information)
- [Community Help and Support](#community-help-and-support)
- [Contributing](#contributing)
![Build badge](https://identitydivision.visualstudio.com/_apis/public/build/definitions/a7934fdd-dcde-4492-a406-7fad6ac00e17/<BuildNumber>/badge)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
![Build badge](https://identitydivision.visualstudio.com/_apis/public/build/definitions/a7934fdd-dcde-4492-a406-7fad6ac00e17/<BuildNumber>/badge)
![Build badge](https://identitydivision.visualstudio.com/_apis/public/build/definitions/a7934fdd-dcde-4492-a406-7fad6ac00e17/<BuildNumber>/badge)

reminder to remove

@@ -0,0 +1,337 @@
---

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the home landing page of the whole tutorial

- Ensure that the **My APIs** tab is selected.
- In the list of APIs, select the API `java-servlet-resource-api`.
- In the **Delegated permissions** section, select the **Access 'java-servlet-resource-api'** in the list. Use the search box if necessary.
- Select the **Add permissions** button at the bottom.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Select

Add a link to use certificates MD file


```Shell
cd project-directory
cd client-web-api

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

client-web-api

no folder by this name?

- Upon successful completion of the sign-in flow, you should be redirected to the home page (`sign in status`) or `token details` page, depending on which button triggered your sign-in flow.
- Note the context-sensitive button now says `Sign out` and displays your username to its left.
- If you are on the home page, you'll see an option to click **ID Token Details**: click it to see some of the ID token's decoded claims.
- You can also use the button on the top right to sign out. The status page will reflect this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to add a step for "call api"


1. Find the resulting `.war` file in `./resource-api/target/msal4j-servlet-api.war` and deploy it to Tomcat or any other J2EE container solution. To deploy to Tomcat, copy this `.war` file to the `/webapps/` directory in your Tomcat installation directory and start the Tomcat server.
1. Ensure that the context path that the app is served on is `/msal4j-servlet-client` (or change the `app.homePage` value in your [authentication.properties](src/main/resources/authentication.properties) file and in the AAD app registration). If you change the properties file, you'll needs to repeat step 3 above (maven clean and package).
1. Open your browser and navigate to `http://localhost:8080/msal4j-servlet-client/`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting error: Server returned HTTP response code: 403 for URL: http://localhost:8080/msal4j-servlet-api/api/date


## About the code

This sample contains two projects. The client uses **MSAL for Java (MSAL4J)** to sign a user in and obtain a token for your API. The client side app is similar to the call-graph sample in chapter 2. The API app processes the incoming request and verifies that it has a valid access token. It leverages Nimbusds library to process and verify the incoming token. Please see the `resource-api/src/main/java.../helpers/JwtVerifier.java` for how the JwtVerifier is set up, and `resource-api/src/main/java.../servlets/AzureAccessTokenFilter.java`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

chapter 2

Provide link


## About the code

This sample contains two projects. The client uses **MSAL for Java (MSAL4J)** to sign a user in and obtain a token for your API. The client side app is similar to the call-graph sample in chapter 2. The API app processes the incoming request and verifies that it has a valid access token. It leverages Nimbusds library to process and verify the incoming token. Please see the `resource-api/src/main/java.../helpers/JwtVerifier.java` for how the JwtVerifier is set up, and `resource-api/src/main/java.../servlets/AzureAccessTokenFilter.java`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nimbusds

link

########################################################################################
#For V1 tokens, uncomment the two values (authority and client ID) in the section below:

aad.clientId=api://Enter_Your_Client_ID_Here

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clientId

this is not client id, but AppID URI

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" href="./static/style.css">
<link rel="icon" type="image/x-icon" href="./static/favicon.ico">
<title>Authentication: Use MSAL Java to sign in users in your Azure Active Directory tenant</title>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Authentication: Use MSAL Java to sign in users in your Azure Active Directory tenant

chnage this

aad.clientId=api://Enter_Your_Client_ID_Here
aad.authority=https://sts.windows.net/Enter_Your_Tenant_ID_Here/


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove all

@derisen
derisen self-requested a review June 28, 2021 20:17

@derisen derisen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Left a bunch of comments for the README

* routes
*/
@WebFilter(filterName = "AzureAccessTokenFilter", urlPatterns = "/*")
public class AzureAccessTokenFilter implements Filter {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AzureAccessTokenFilter

nit:change to AzureADAccessTokenFilter

// make an instance of the verifier (found in helpers.JwtVerifier)
// use AUTHORITY value from config for issuer.
// use CLIENT_ID value from config for audience.
// use SCOPES value from config for scopes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

heavil;y comment all that will be validated


/**
* This class defines the endpoint for showing the graph /me endpoint
* This is here simply to demonstrate the graph call.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

really??

@sangonzal sangonzal left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great progress

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are we using this file for?

@Override
protected void doGet(final HttpServletRequest req, final HttpServletResponse resp)
throws ServletException, IOException {
logger.log(Level.FINE, "Request has come with params {0}", req.getQueryString());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reminder for removing this line log statement.

* format:'{group-id} /protected-route-1
* /protected-route-2 /protected-route-N'
*/
public ProtectedRoutes(List<String> authRoutes, List<String> groupNameAndRoutes, List<String> roleNameAndRoutes,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like groupNameAndRoutes and roleNameAndRoutes never get used?

import java.io.InputStreamReader;
import java.net.HttpURLConnection;


Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: extra line

}
}

private static class NetClient {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use the Graph SDK here instead?

Comment on lines +82 to +89
/**
* AAD has many aliases. We need to account for this when verifying
* @return
*/

private void issuerVerifier() {

}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dead code

// RSA keys sourced from the JWK set URL
return new JWSVerificationKeySelector<>(expectedJWSAlg, keySource);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra space

// if the verification is successful, you'll receive a JWTClaimsSet
JWTClaimsSet claimsSet = verifier.getJWTClaimsSet(accessToken);
// put it into the request so the request handling servlet can make use of its claims as neeed.
req.setAttribute("accessToken", claimsSet);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: consider renaming this attribute to accessTokenClaims

Comment on lines +87 to +94
String msg = String.format("An error occurred when validating the JWT signature: %s", e.getMessage());
logger.log(Level.WARNING, msg);
HttpServletResponse httpResponse = (HttpServletResponse) res;
PrintWriter out;
out = httpResponse.getWriter();
httpResponse.setStatus(403);
out.write(msg);
out.close();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know what kind of information Spring/Identity Web return to the caller when JWT validation fails? I ask because we might not want to return any information about the JWT validation error to callers, as this could be a security vulnerability.

Also we can discuss this in person but I think 401 status code might be a bit more appropriate here. I see 401 as saying, "Unauthenticated" or "Could not validate your identity", while 403 is "Unauthorized" or "Validated your identity, but you don't have the permissions to access this specific resource"

Comment on lines +46 to +51
PrintWriter out;
out = resp.getWriter();
resp.setContentType("text/html");
resp.setStatus(200);
out.write(dateAsJson());
out.close();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested:

        
        resp.setContentType("text/html");
        resp.setStatus(200);
        PrintWriter out = resp.getWriter();
        out.write(dateAsJson());
        out.close();

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants