1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package davmail.exchange.auth;
21
22 import davmail.Settings;
23 import davmail.http.HttpClientAdapter;
24 import davmail.http.request.RestRequest;
25 import org.apache.http.Consts;
26 import org.apache.http.NameValuePair;
27 import org.apache.http.client.entity.UrlEncodedFormEntity;
28 import org.apache.http.client.methods.CloseableHttpResponse;
29 import org.apache.http.message.BasicNameValuePair;
30 import org.apache.log4j.Logger;
31 import org.codehaus.jettison.json.JSONException;
32 import org.codehaus.jettison.json.JSONObject;
33
34 import java.io.IOException;
35 import java.net.URI;
36 import java.util.ArrayList;
37
38 public class O365DeviceCodeAuthenticator implements ExchangeAuthenticator {
39 protected static final Logger LOGGER = Logger.getLogger(O365DeviceCodeAuthenticator.class);
40
41 protected static class DeviceCode {
42 final private String deviceCode;
43 final private String message;
44
45 DeviceCode(String deviceCode, String message) {
46 this.deviceCode = deviceCode;
47 this.message = message;
48 }
49
50 public String getDeviceCode() {
51 return deviceCode;
52 }
53
54 public String getMessage() {
55 return message;
56 }
57 }
58
59 private String username;
60 private String password;
61 private O365Token token;
62 URI ewsUrl = URI.create(Settings.getO365Url());
63
64 @Override
65 public void setUsername(String username) {
66 this.username = username;
67 }
68
69 @Override
70 public void setPassword(String password) {
71 this.password = password;
72 }
73
74 @Override
75 public void authenticate() throws IOException {
76
77 final String clientId = Settings.getProperty("davmail.oauth.clientId", "facd6cff-a294-4415-b59f-c5b01937d7bd");
78 String resource;
79 if (Settings.getBooleanProperty("davmail.enableGraph", false)) {
80 resource = Settings.getGraphUrl();
81 } else {
82 resource = Settings.getOutlookUrl();
83 }
84
85
86 String tenantId = Settings.getProperty("davmail.oauth.tenantId", "common");
87
88
89 token = O365Token.load(tenantId, clientId, "", username, password);
90 if (token != null) {
91 return;
92 }
93
94
95 String url;
96
97 DeviceCode deviceCode;
98 ArrayList<NameValuePair> parameters = new ArrayList<>();
99 parameters.add(new BasicNameValuePair("client_id", clientId));
100 if (Settings.getBooleanProperty("davmail.enableOidc", false)) {
101 url = Settings.getO365LoginUrl() + "/" + tenantId + "/oauth2/v2.0/devicecode?api-version=1.0";
102 parameters.add(new BasicNameValuePair("scope", Settings.getOauthScope()));
103 } else {
104 url = Settings.getO365LoginUrl() + "/" + tenantId + "/oauth2/devicecode?api-version=1.0";
105 parameters.add(new BasicNameValuePair("resource", resource));
106 }
107
108 RestRequest logonMethod = new RestRequest(url, new UrlEncodedFormEntity(parameters, Consts.UTF_8));
109
110 try (
111 HttpClientAdapter httpClientAdapter = new HttpClientAdapter(url);
112 CloseableHttpResponse response = httpClientAdapter.execute(logonMethod)
113 ) {
114
115 JSONObject deviceCodeResponse = logonMethod.handleResponse(response);
116 final String error = deviceCodeResponse.optString("error_description", deviceCodeResponse.optString("error", null));
117 if (error != null) {
118 throw new IOException("Exception getting device code: " + error);
119 }
120 deviceCode = new DeviceCode(deviceCodeResponse.getString("device_code"), deviceCodeResponse.getString("message"));
121 } catch (JSONException e) {
122 throw new IOException("Exception parsing device code", e);
123 }
124
125
126 try {
127 while (token == null) {
128 System.out.println(deviceCode.getMessage());
129
130
131 Thread.sleep(5000);
132
133 try {
134 token = O365Token.build(tenantId, clientId, deviceCode, password);
135 } catch (O365AuthorizationPending e) {
136 LOGGER.error("Authorization pending for device code");
137 }
138 }
139 } catch (InterruptedException e) {
140 LOGGER.error("Interrupted waiting for token " + e.getMessage());
141 Thread.currentThread().interrupt();
142 }
143
144 }
145
146 @Override
147 public O365Token getToken() throws IOException {
148 return token;
149 }
150
151 @Override
152 public URI getExchangeUri() {
153 return ewsUrl;
154 }
155
156 @Override
157 public HttpClientAdapter getHttpClientAdapter() {
158 return new HttpClientAdapter(getExchangeUri(), username, password, true);
159 }
160
161 public static void main(String[] argv) throws IOException {
162 Settings.setDefaultSettings();
163 Settings.setProperty("davmail.server", "false");
164
165
166 O365DeviceCodeAuthenticator authenticator = new O365DeviceCodeAuthenticator();
167 authenticator.setUsername("");
168 authenticator.authenticate();
169 }
170 }