Skip to content

Commit

Permalink
Merge pull request #133 from AzureAD/dev
Browse files Browse the repository at this point in the history
1.1.0 Release
  • Loading branch information
sangonzal authored Nov 22, 2019
2 parents 27da5b9 + 3a00e31 commit c6d9599
Show file tree
Hide file tree
Showing 43 changed files with 1,172 additions and 834 deletions.
40 changes: 27 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,59 @@
--------------------|-----------------|---------------
[![Build status](https://identitydivision.visualstudio.com/IDDP/_apis/build/status/CI/Java/MSAL%20Java%20CI%20Build?branchName=master)](https://identitydivision.visualstudio.com/IDDP/_build/latest?definitionId=762) | [![Build status](https://identitydivision.visualstudio.com/IDDP/_apis/build/status/CI/Java/MSAL%20Java%20CI%20Build?branchName=dev)](https://identitydivision.visualstudio.com/IDDP/_build/latest?definitionId=762)| [![Javadocs](http://javadoc.io/badge/com.microsoft.azure/msal4j.svg)](http://javadoc.io/doc/com.microsoft.azure/msal4j)

|[Getting Started](https://github.com/AzureAD/microsoft-authentication-library-for-java/wiki)| [Docs](https://aka.ms/aaddev)| [Support](README.md#community-help-and-support)
| --- | --- | --- |
The Microsoft Authentication Library for Java (MSAL4J) enables applications to integrate with the [Microsoft identity platform](https://aka.ms/aaddevv2). It allows you to sign in users or apps with Microsoft identities (Azure AD, Microsoft accounts and Azure AD B2C accounts) and obtain tokens to call Microsoft APIs such as [Microsoft Graph](https://graph.microsoft.io/) or your own APIs registered with the Microsoft identity platform. It is built using industry standard OAuth2 and OpenID Connect protocols.

The MSAL library for Java gives your app the ability to begin using the Microsoft Cloud by supporting Microsoft Azure Active Directory and Microsoft Accounts in a converged experience using industry standard OAuth2 and OpenID Connect.
Quick links:

| [Getting Started](https://docs.microsoft.com/azure/active-directory/develop/quickstart-v2-java-webapp) | [Docs](https://github.com/AzureAD/microsoft-authentication-library-for-java/wiki) | [Samples](https://aka.ms/aaddevsamplesv2) | [Support](README.md#community-help-and-support)
| --- | --- | --- | --- |

## Versions
Current version - 1.0.0
## Install
Current version - 1.1.0

You can find the changes for each version in the [change log](https://github.com/AzureAD/microsoft-authentication-library-for-java/blob/master/changelog.txt).

You can get the msal4j package through Maven or Gradle.

### Maven

```
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>msal4j</artifactId>
<version>1.0.0</version>
<version>1.1.0</version>
</dependency>
```
### Gradle

```
compile group: 'com.microsoft.azure', name: 'msal4j', version: '1.0.0'
compile group: 'com.microsoft.azure', name: 'msal4j', version: '1.1.0'
```

## Usage

MSAL4J supports multiple [application types and authentication scenarios](https://docs.microsoft.com/azure/active-directory/develop/authentication-flows-app-scenarios).

Refer the [Wiki](https://github.com/AzureAD/microsoft-authentication-library-for-java/wiki) pages for more details on the usage of MSAL Java and the supported scenarios.

## Migrating from ADAL
If your application is using ADAL for Java (ADAL4J), we recommend you to update to use MSAL4J. No new feature work will be done in ADAL4J.

See the [ADAL to MSAL migration](https://github.com/AzureAD/microsoft-authentication-library-for-java/wiki/Migrate-to-MSAL-Java) guide.

## Roadmap

You can follow the latest updates and plans for MSAL Java in the [Roadmap](https://github.com/AzureAD/microsoft-authentication-library-for-java/wiki#roadmap) published on our Wiki.

## Contribution

This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com.
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.

## Build and Run

Refer [this page](https://github.com/AzureAD/microsoft-authentication-library-for-java/wiki/Maven)

## Samples and Documentation

We provide a [full suite of sample applications](https://github.com/Azure-Samples) and [documentation](https://aka.ms/aaddev) to help you get started with learning the Azure Identity system. This includes tutorials for native clients such as Windows, Windows Phone, iOS, macOS, Android, and Linux. We also provide full walkthroughs for authentication flows such as OAuth2, OpenID Connect, Graph API, and other awesome features.
We provide a [full suite of sample applications](https://aka.ms/aaddevsamplesv2) and [documentation](https://aka.ms/aaddevv2) to help you get started with learning the Microsoft identity platform.

## Community Help and Support

Expand All @@ -52,7 +66,7 @@ We recommend you use the "msal" tag so we can see it! Here is the latest Q&A on

## Security Reporting

If you find a security issue with our libraries or services please report it to [[email protected]](mailto:[email protected]) with as much detail as possible. Your submission may be eligible for a bounty through the [Microsoft Bounty](http://aka.ms/bugbounty) program. Please do not post security issues to GitHub Issues or any other public site. We will contact you shortly upon receiving the information. We encourage you to get notifications of when security incidents occur by visiting [this page](https://technet.microsoft.com/en-us/security/dd252948) and subscribing to Security Advisory Alerts.
If you find a security issue with our libraries or services please report it to [[email protected]](mailto:[email protected]) with as much detail as possible. Your submission may be eligible for a bounty through the [Microsoft Bounty](http://aka.ms/bugbounty) program. Please do not post security issues to GitHub Issues or any other public site. We will contact you shortly upon receiving the information. We encourage you to get notifications of when security incidents occur by visiting [this page](https://technet.microsoft.com/security/dd252948) and subscribing to Security Advisory Alerts.

## We Value and Adhere to the Microsoft Open Source Code of Conduct

Expand Down
4 changes: 4 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
Version 1.1.0
=============
- Added support for configuring HTTP client

Version 1.0.0
=============
- API surface is now stable and production ready. No breaking changes will be introduced without incrementing MAJOR version
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.microsoft.azure</groupId>
<artifactId>msal4j</artifactId>
<version>1.0.0</version>
<version>1.1.0</version>
<packaging>jar</packaging>
<name>msal4j</name>
<description>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.microsoft.aad.msal4j;

import org.apache.http.Header;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

class ApacheHttpClientAdapter implements IHttpClient {

private CloseableHttpClient httpClient;

ApacheHttpClientAdapter(){
this.httpClient = HttpClients.createDefault();
}

@Override
public IHttpResponse send(HttpRequest httpRequest) throws Exception {

HttpRequestBase request = buildApacheRequestFromMsalRequest(httpRequest);
CloseableHttpResponse response = httpClient.execute(request);

return buildMsalResponseFromApacheResponse(response);
}


private HttpRequestBase buildApacheRequestFromMsalRequest(HttpRequest httpRequest){

if(httpRequest.httpMethod() == HttpMethod.GET){
return builGetRequest(httpRequest);
} else if(httpRequest.httpMethod() == HttpMethod.POST){
return buildPostRequest(httpRequest);
} else {
throw new IllegalArgumentException("HttpRequest method should be either GET or POST");
}
}

private HttpGet builGetRequest(HttpRequest httpRequest){
HttpGet httpGet = new HttpGet(httpRequest.url().toString());

for(Map.Entry<String, String> entry: httpRequest.headers().entrySet()){
httpGet.setHeader(entry.getKey(), entry.getValue());
}

return httpGet;
}

private HttpPost buildPostRequest(HttpRequest httpRequest){

HttpPost httpPost = new HttpPost(httpRequest.url().toString());
for(Map.Entry<String, String> entry: httpRequest.headers().entrySet()){
httpPost.setHeader(entry.getKey(), entry.getValue());
}

String contentTypeHeaderValue = httpRequest.headerValue("Content-Type");
ContentType contentType = ContentType.getByMimeType(contentTypeHeaderValue);
StringEntity stringEntity = new StringEntity(httpRequest.body(), contentType);

httpPost.setEntity(stringEntity);
return httpPost;
}

private IHttpResponse buildMsalResponseFromApacheResponse(CloseableHttpResponse apacheResponse)
throws IOException {

IHttpResponse httpResponse = new HttpResponse();
((HttpResponse) httpResponse).statusCode(apacheResponse.getStatusLine().getStatusCode());

Map<String, List<String>> headers = new HashMap<>();
for(Header header: apacheResponse.getAllHeaders()){
headers.put(header.getName(), Collections.singletonList(header.getValue()));
}
((HttpResponse) httpResponse).headers(headers);

String responseBody = EntityUtils.toString(apacheResponse.getEntity(), "UTF-8");
((HttpResponse) httpResponse).body(responseBody);
return httpResponse;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.microsoft.aad.msal4j;

import labapi.LabResponse;
import labapi.LabUserProvider;
import labapi.NationalCloud;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import java.util.Collections;

public class HttpClientIT {
private LabUserProvider labUserProvider;

@BeforeClass
public void setUp() {
labUserProvider = LabUserProvider.getInstance();
}

@Test
public void acquireToken_okHttpClient() throws Exception {

LabResponse labResponse = getManagedUserAccountWithPassword();
assertAcquireTokenCommon(labResponse, new OkHttpClientAdapter());
}

@Test
public void acquireToken_apacheHttpClient() throws Exception {

LabResponse labResponse = getManagedUserAccountWithPassword();
assertAcquireTokenCommon(labResponse, new ApacheHttpClientAdapter());
}

private void assertAcquireTokenCommon(LabResponse labResponse, IHttpClient httpClient)
throws Exception{
PublicClientApplication pca = PublicClientApplication.builder(
labResponse.getAppId()).
authority(TestConstants.ORGANIZATIONS_AUTHORITY).
httpClient(httpClient).
build();

IAuthenticationResult result = pca.acquireToken(UserNamePasswordParameters.
builder(Collections.singleton(TestConstants.GRAPH_DEFAULT_SCOPE),
labResponse.getUser().getUpn(),
labResponse.getUser().getPassword().toCharArray())
.build())
.get();

Assert.assertNotNull(result);
Assert.assertNotNull(result.accessToken());
Assert.assertNotNull(result.idToken());
Assert.assertEquals(labResponse.getUser().getUpn(), result.account().username());
}

private LabResponse getManagedUserAccountWithPassword(){
LabResponse labResponse = labUserProvider.getDefaultUser(
NationalCloud.AZURE_CLOUD,
false);
labUserProvider.getUserPassword(labResponse.getUser());

return labResponse;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.microsoft.aad.msal4j;

import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;

import java.io.IOException;

class OkHttpClientAdapter implements IHttpClient{

private OkHttpClient client;

OkHttpClientAdapter(){
this.client = new OkHttpClient();
}

@Override
public IHttpResponse send(HttpRequest httpRequest) throws IOException {

Request request = buildOkRequestFromMsalRequest(httpRequest);

Response okHttpResponse= client.newCall(request).execute();
return buildMsalResponseFromOkResponse(okHttpResponse);
}

private Request buildOkRequestFromMsalRequest(HttpRequest httpRequest){

if(httpRequest.httpMethod() == HttpMethod.GET){
return buildGetRequest(httpRequest);
} else if(httpRequest.httpMethod() == HttpMethod.POST){
return buildPostRequest(httpRequest);
} else {
throw new IllegalArgumentException("HttpRequest method should be either GET or POST");
}
}

private Request buildGetRequest(HttpRequest httpRequest){
Headers headers = Headers.of(httpRequest.headers());

return new Request.Builder()
.url(httpRequest.url())
.headers(headers)
.build();
}

private Request buildPostRequest(HttpRequest httpRequest){
Headers headers = Headers.of(httpRequest.headers());
String contentType = httpRequest.headerValue("Content-Type");
MediaType type = MediaType.parse(contentType);

RequestBody requestBody = RequestBody.create(type, httpRequest.body());

return new Request.Builder()
.url(httpRequest.url())
.post(requestBody)
.headers(headers)
.build();
}

private IHttpResponse buildMsalResponseFromOkResponse(Response okHttpResponse) throws IOException{

IHttpResponse httpResponse = new HttpResponse();
((HttpResponse) httpResponse).statusCode(okHttpResponse.code());

ResponseBody body = okHttpResponse.body();
if(body != null){
((HttpResponse) httpResponse).body(body.string());
}

Headers headers = okHttpResponse.headers();
if(headers != null){
((HttpResponse) httpResponse).headers(headers.toMultimap());
}
return httpResponse;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public void acquireTokenWithUsernamePassword_ADFSv2() throws Exception{
assertAcquireTokenCommon(labResponse, password);
}

public void assertAcquireTokenCommon(LabResponse labResponse, String password)
private void assertAcquireTokenCommon(LabResponse labResponse, String password)
throws Exception{
PublicClientApplication pca = PublicClientApplication.builder(
labResponse.getAppId()).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ private IClientCredential getClientCredentialFromKeyStore() {
key = (PrivateKey) keystore.getKey(CERTIFICATE_ALIAS, null);
publicCertificate = (X509Certificate) keystore.getCertificate(
CERTIFICATE_ALIAS);

} catch (Exception e){
throw new RuntimeException("Error getting certificate from keystore: " + e.getMessage());
}
Expand Down
13 changes: 8 additions & 5 deletions src/main/java/com/microsoft/aad/msal4j/AadInstanceDiscovery.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,21 @@ private static String getInstanceDiscoveryEndpoint(String host) {

private static InstanceDiscoveryResponse sendInstanceDiscoveryRequest
(URL authorityUrl, MsalRequest msalRequest,
ServiceBundle serviceBundle) throws Exception {
ServiceBundle serviceBundle) {

String instanceDiscoveryRequestUrl = getInstanceDiscoveryEndpoint(authorityUrl.getAuthority()) +
INSTANCE_DISCOVERY_REQUEST_PARAMETERS_TEMPLATE.replace("{authorizeEndpoint}",
getAuthorizeEndpoint(authorityUrl.getAuthority(),
Authority.getTenant(authorityUrl, Authority.detectAuthorityType(authorityUrl))));

String json = HttpHelper.executeHttpRequest
(log, HttpMethod.GET, instanceDiscoveryRequestUrl, msalRequest.headers().getReadonlyHeaderMap(),
null, msalRequest.requestContext(), serviceBundle);
HttpRequest httpRequest = new HttpRequest(
HttpMethod.GET,
instanceDiscoveryRequestUrl,
msalRequest.headers().getReadonlyHeaderMap());

return JsonHelper.convertJsonToObject(json, InstanceDiscoveryResponse.class);
IHttpResponse httpResponse= HttpHelper.executeHttpRequest(httpRequest, msalRequest.requestContext(), serviceBundle);

return JsonHelper.convertJsonToObject(httpResponse.body(), InstanceDiscoveryResponse.class);
}

private static void validate(InstanceDiscoveryResponse instanceDiscoveryResponse) {
Expand Down
Loading

0 comments on commit c6d9599

Please sign in to comment.