Skip to content
This repository was archived by the owner on Aug 28, 2024. It is now read-only.

Commit 3d92eb6

Browse files
authored
Spring Social support for Microsoft Graph (#121)
1 parent 3be5eec commit 3d92eb6

File tree

35 files changed

+1964
-89
lines changed

35 files changed

+1964
-89
lines changed

common/azure-spring-boot-starter-parent/pom.xml

+3-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,9 @@
128128
<show>private</show>
129129
<failOnError>false</failOnError>
130130
<sourceFileExcludes>
131-
<exclude>com/microsoft/azure/spring/data/documentdb/core/mapping/BasicDocumentDbPersistentProperty.java</exclude>
131+
<exclude>
132+
com/microsoft/azure/spring/data/documentdb/core/mapping/BasicDocumentDbPersistentProperty.java
133+
</exclude>
132134
</sourceFileExcludes>
133135
</configuration>
134136
<executions>

common/config/findbugs-exclude.xml

+1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@
55
<Bug pattern="NP_NONNULL_PARAM_VIOLATION"/>
66
<Bug pattern="Unwritten field"/>
77
<Bug pattern="SIC_INNER_SHOULD_BE_STATIC_ANON"/>
8+
<Bug pattern="UUF_UNUSED_PUBLIC_OR_PROTECTED_FIELD"/>
89
</FindBugsFilter>

microsoft-graph/microsoft-graph-spring-boot-autoconfigure/pom.xml

+10-5
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,6 @@
5454
<groupId>org.springframework.social</groupId>
5555
<artifactId>spring-social-config</artifactId>
5656
</dependency>
57-
<dependency>
58-
<groupId>org.springframework.boot</groupId>
59-
<artifactId>spring-boot-starter-test</artifactId>
60-
<scope>test</scope>
61-
</dependency>
6257
<dependency>
6358
<groupId>org.springframework.boot</groupId>
6459
<artifactId>spring-boot-starter-validation</artifactId>
@@ -67,5 +62,15 @@
6762
<groupId>com.microsoft.azure</groupId>
6863
<artifactId>spring-social-microsoft-graph</artifactId>
6964
</dependency>
65+
<dependency>
66+
<groupId>org.springframework.boot</groupId>
67+
<artifactId>spring-boot-starter-test</artifactId>
68+
<scope>test</scope>
69+
</dependency>
70+
<dependency>
71+
<groupId>org.springframework.boot</groupId>
72+
<artifactId>spring-boot-starter-web</artifactId>
73+
<scope>test</scope>
74+
</dependency>
7075
</dependencies>
7176
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See LICENSE in the project root for
4+
* license information.
5+
*/
6+
package com.microsoft.azure.autoconfigure.msgraph;
7+
8+
public class Constants {
9+
public static final String APP_ID_PROPERTY = "spring.social.microsoft.app-id";
10+
public static final String APP_ID = "123456789-acb1-4d0b-a13b-1a70ac85d8bf";
11+
public static final String APP_SECRET_PROPERTY = "spring.social.microsoft.app-secret";
12+
public static final String APP_SECRET = "1234mAocWmbvawgg4hyRTZ8";
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See LICENSE in the project root for
4+
* license information.
5+
*/
6+
7+
package com.microsoft.azure.autoconfigure.msgraph;
8+
9+
import com.microsoft.azure.msgraph.api.Microsoft;
10+
import org.assertj.core.api.Assertions;
11+
import org.junit.Test;
12+
import org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration;
13+
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
14+
15+
import static org.assertj.core.api.Java6Assertions.assertThat;
16+
17+
public class MicrosoftAutoConfigurationTest {
18+
@Test
19+
public void canAutowire() {
20+
System.setProperty(Constants.APP_ID_PROPERTY, Constants.APP_ID);
21+
System.setProperty(Constants.APP_SECRET_PROPERTY, Constants.APP_SECRET);
22+
23+
try (AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext()) {
24+
context.register(MicrosoftAutoConfiguration.class);
25+
context.register(SocialWebAutoConfiguration.class);
26+
context.refresh();
27+
Assertions.assertThat(context.getBean(Microsoft.class)).isNotNull();
28+
}
29+
30+
System.clearProperty(Constants.APP_ID_PROPERTY);
31+
System.clearProperty(Constants.APP_SECRET_PROPERTY);
32+
}
33+
34+
@Test
35+
public void cannotAutowire() {
36+
try (AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext()) {
37+
context.register(MicrosoftAutoConfiguration.class);
38+
context.register(SocialWebAutoConfiguration.class);
39+
context.refresh();
40+
41+
Microsoft microsoft = null;
42+
try {
43+
microsoft = context.getBean(Microsoft.class);
44+
} catch (Exception e) {
45+
assertThat(e.getMessage()).contains("No qualifying bean of type 'com.microsoft.azure." +
46+
"msgraph.api.Microsoft' available");
47+
}
48+
assertThat(microsoft).isNull();
49+
}
50+
}
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See LICENSE in the project root for
4+
* license information.
5+
*/
6+
7+
package com.microsoft.azure.autoconfigure.msgraph;
8+
9+
import org.junit.Test;
10+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
11+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
12+
import org.springframework.context.annotation.Configuration;
13+
14+
import static org.assertj.core.api.Assertions.assertThat;
15+
16+
public class MicrosoftPropertiesTest {
17+
@Test
18+
public void canSetProperties() {
19+
System.setProperty(Constants.APP_ID_PROPERTY, Constants.APP_ID);
20+
System.setProperty(Constants.APP_SECRET_PROPERTY, Constants.APP_SECRET);
21+
22+
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
23+
context.register(Config.class);
24+
context.refresh();
25+
final MicrosoftProperties properties = context.getBean(MicrosoftProperties.class);
26+
27+
assertThat(properties.getAppId()).isEqualTo(Constants.APP_ID);
28+
assertThat(properties.getAppSecret()).isEqualTo(Constants.APP_SECRET);
29+
}
30+
31+
System.clearProperty(Constants.APP_ID_PROPERTY);
32+
System.clearProperty(Constants.APP_SECRET_PROPERTY);
33+
}
34+
35+
@Configuration
36+
@EnableConfigurationProperties(MicrosoftProperties.class)
37+
static class Config {
38+
}
39+
}

microsoft-graph/microsoft-graph-spring-social-starter-sample/README.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,9 @@ Go to [Application Registration Portal](https://apps.dev.microsoft.com/#/appList
3434
```
3535
mvn package
3636
java -jar target/microsoft-graph-spring-social-starter-sample-0.0.1-SNAPSHOT.jar
37-
```
37+
```
38+
39+
### Make your own REST API call
40+
41+
This starter implements a small subset of Objects/APIs available via Microsoft Graph (GET /me, POST /me/sendMail, GET /me/messages). In addition, it demonstrates how to make custom REST API calls (see function `getContacts` in `HelloController.java` as an example). Please check the detailed [document](https://developer.microsoft.com/en-us/graph/docs/concepts/overview) for more details about Microsoft Graph.
42+
After reading the document, you should be aware of the exact REST API and what objects you should prepare or expect from the REST API call.

microsoft-graph/microsoft-graph-spring-social-starter-sample/src/main/java/sample/microsoft/graph/HelloController.java

+19-5
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010
import org.springframework.social.connect.ConnectionRepository;
1111
import org.springframework.stereotype.Controller;
1212
import org.springframework.ui.Model;
13-
import org.springframework.web.bind.annotation.GetMapping;
1413
import org.springframework.web.bind.annotation.RequestMapping;
14+
import org.springframework.web.client.RestTemplate;
15+
import sample.microsoft.graph.custom.Contacts;
16+
17+
import java.net.URI;
1518

1619
@Controller
17-
@RequestMapping("/")
1820
public class HelloController {
19-
2021
private Microsoft microsoft;
2122
private ConnectionRepository connectionRepository;
2223

@@ -25,8 +26,8 @@ public HelloController(Microsoft microsoft, ConnectionRepository connectionRepos
2526
this.connectionRepository = connectionRepository;
2627
}
2728

28-
@GetMapping
29-
public String helloFacebook(Model model) {
29+
@RequestMapping("/")
30+
public String helloMicrosoft(Model model) {
3031
if (connectionRepository.findPrimaryConnection(Microsoft.class) == null) {
3132
return "redirect:/connect/microsoft";
3233
}
@@ -36,4 +37,17 @@ public String helloFacebook(Model model) {
3637
return "hello";
3738
}
3839

40+
@RequestMapping("/contacts")
41+
public String getContacts(Model model) {
42+
if (connectionRepository.findPrimaryConnection(Microsoft.class) == null) {
43+
return "redirect:/connect/microsoft";
44+
}
45+
46+
final RestTemplate restTemplate = microsoft.customOperations().getRestTemplate();
47+
final URI uri = microsoft.customOperations().getGraphAPIURI("me/contacts");
48+
final Contacts contacts = restTemplate.getForObject(uri, Contacts.class);
49+
model.addAttribute("contacts", contacts.getContacts());
50+
51+
return "contacts";
52+
}
3953
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See LICENSE in the project root for
4+
* license information.
5+
*/
6+
7+
package sample.microsoft.graph.custom;
8+
9+
// Please be noted this is not a complete representation of the JSON object returned by Microsoft Graph.
10+
public class Contact {
11+
12+
private String displayName;
13+
private String mobilePhone;
14+
15+
/**
16+
* The Display Name.
17+
*/
18+
public String getDisplayName() {
19+
return displayName;
20+
}
21+
22+
public void setDisplayName(String displayName) {
23+
this.displayName = displayName;
24+
}
25+
26+
/**
27+
* The Mobile Phone.
28+
*/
29+
public String getMobilePhone() {
30+
return mobilePhone;
31+
}
32+
33+
public void setMobilePhone(String mobilePhone) {
34+
this.mobilePhone = mobilePhone;
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See LICENSE in the project root for
4+
* license information.
5+
*/
6+
7+
package sample.microsoft.graph.custom;
8+
9+
import com.fasterxml.jackson.annotation.JsonProperty;
10+
11+
public class Contacts {
12+
@JsonProperty("value")
13+
private java.util.List<Contact> contacts;
14+
15+
@JsonProperty("@odata.nextLink")
16+
private String nextLink;
17+
18+
public java.util.List<Contact> getContacts() {
19+
return contacts;
20+
}
21+
22+
public void setContacts(java.util.List<Contact> contacts) {
23+
this.contacts = contacts;
24+
}
25+
26+
/**
27+
* The url to the next page of this collection, or null
28+
*/
29+
public String getNextLink() {
30+
return nextLink;
31+
}
32+
33+
public void setNextLink(String nextLink) {
34+
this.nextLink = nextLink;
35+
}
36+
}

microsoft-graph/microsoft-graph-spring-social-starter-sample/src/main/resources/templates/connect/microsoftConnect.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<h3>Connect to Microsoft Graph</h3>
77

88
<form action="/connect/microsoft" method="POST">
9-
<input type="hidden" name="scope" value="User.Read"/>
9+
<input type="hidden" name="scope" value="User.Read Contacts.Read"/>
1010
<div class="formInfo">
1111
<p>You aren't connected to Microsoft yet. Click the button to connect this application with your Microsoft
1212
account.</p>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<html>
2+
<head>
3+
<title>Hello Microsoft Graph</title>
4+
</head>
5+
<body>
6+
<table>
7+
<tr>
8+
<th>Name</th>
9+
<th>Phone</th>
10+
</tr>
11+
<tr th:each="contact : ${contacts}">
12+
<td th:text="${contact.getDisplayName()}"/>
13+
<td th:text="${contact.getMobilePhone()}"/>
14+
</tr>
15+
</table>
16+
</body>
17+
</html>

microsoft-graph/microsoft-graph-spring-social-starter-sample/src/main/resources/templates/hello.html

+4
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@
4848
<th>User Principal Name</th>
4949
<td th:text="${user.userPrincipalName}"/>
5050
</tr>
51+
<tr>
52+
<th>Contacts</th>
53+
<td><a href="/contacts.html">click here</a></td>
54+
</tr>
5155
</table>
5256
</body>
5357
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See LICENSE in the project root for
4+
* license information.
5+
*/
6+
7+
package com.microsoft.azure.msgraph.api;
8+
9+
/**
10+
* The Enum Body Type.
11+
*/
12+
public enum BodyType {
13+
/**
14+
* text
15+
*/
16+
text,
17+
/**
18+
* html
19+
*/
20+
html,
21+
/**
22+
* For BodyType values that were not expected from the service
23+
*/
24+
unexpectedValue
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/**
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See LICENSE in the project root for
4+
* license information.
5+
*/
6+
7+
package com.microsoft.azure.msgraph.api;
8+
9+
import org.springframework.web.client.RestTemplate;
10+
11+
import java.net.URI;
12+
13+
public interface CustomOperations {
14+
public RestTemplate getRestTemplate();
15+
16+
public URI getGraphAPIURI(String relativePath);
17+
}

0 commit comments

Comments
 (0)