View Javadoc
1   /*
2    * DavMail POP/IMAP/SMTP/CalDav/LDAP Exchange Gateway
3    * Copyright (C) 2010  Mickael Guessant
4    *
5    * This program is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU General Public License
7    * as published by the Free Software Foundation; either version 2
8    * of the License, or (at your option) any later version.
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with this program; if not, write to the Free Software
17   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18   */
19  
20  package davmail.exchange.auth;
21  
22  import davmail.BundleMessage;
23  import davmail.Settings;
24  import davmail.ui.tray.DavGatewayTray;
25  import davmail.ui.tray.SwtGatewayTray;
26  import org.apache.log4j.Logger;
27  import org.eclipse.swt.SWT;
28  import org.eclipse.swt.SWTError;
29  import org.eclipse.swt.browser.Browser;
30  import org.eclipse.swt.browser.LocationEvent;
31  import org.eclipse.swt.browser.LocationListener;
32  import org.eclipse.swt.layout.FillLayout;
33  import org.eclipse.swt.widgets.Display;
34  import org.eclipse.swt.widgets.Shell;
35  
36  /**
37   * Alternative embedded browser implementation based on SWT instead of OpenJFX
38   */
39  public class O365InteractiveAuthenticatorSWT {
40  
41      private static final Logger LOGGER = Logger.getLogger(O365InteractiveAuthenticatorSWT.class);
42  
43      private O365InteractiveAuthenticator authenticator;
44  
45      Shell shell;
46      Browser browser;
47      private final Object LOCK = new Object();
48      private boolean isReady = false;
49      private SWTError error;
50  
51      public O365InteractiveAuthenticatorSWT() {
52  
53      }
54  
55      public void setO365InteractiveAuthenticator(O365InteractiveAuthenticator authenticator) {
56          this.authenticator = authenticator;
57      }
58  
59      public void authenticate(final String initUrl, final String redirectUri) {
60          // initialize SWT
61          SwtGatewayTray.initDisplay();
62  
63          // allow SSO on windows
64          System.setProperty("org.eclipse.swt.browser.Edge.allowSingleSignOnUsingOSPrimaryAccount",
65                  Settings.getProperty("davmail.oauth.allowSingleSignOnUsingOSPrimaryAccount", "true"));
66  
67          Display.getDefault().asyncExec(() -> {
68              try {
69                  shell = new Shell(Display.getDefault());
70                  shell.setText(BundleMessage.format("UI_DAVMAIL_GATEWAY"));
71                  shell.setSize(600, 600);
72  
73                  shell.setLayout(new FillLayout());
74  
75                  shell.setImage(SwtGatewayTray.loadSwtImage("tray.png", 32));
76  
77                  shell.addListener(SWT.Close, event -> {
78                      if (!authenticator.isAuthenticated && authenticator.errorCode == null) {
79                          authenticator.errorCode = "user closed authentication window";
80                      }
81                      dispose();
82                  });
83  
84                  browser = new Browser(shell, SWT.NONE);
85  
86                  browser.setUrl(initUrl);
87                  browser.addTitleListener(titleEvent -> shell.setText("DavMail: " + titleEvent.title));
88                  browser.addLocationListener(new LocationListener() {
89                      @Override
90                      public void changing(LocationEvent locationEvent) {
91                          LOGGER.debug("Navigate to " + locationEvent.toString());
92                          String location = locationEvent.location;
93  
94                          if (location.startsWith(redirectUri)) {
95  
96                              LOGGER.debug("Location starts with redirectUri, check code");
97                              authenticator.handleCode(location);
98  
99                              shell.close();
100                             dispose();
101                         }
102 
103                     }
104 
105                     @Override
106                     public void changed(LocationEvent locationEvent) {
107                         LOGGER.debug("Page changed: " + locationEvent.toString());
108                     }
109                 });
110 
111                 synchronized (LOCK) {
112                     // ready
113                     isReady = true;
114                     LOCK.notifyAll();
115                 }
116 
117                 shell.open();
118                 shell.setActive();
119             } catch (SWTError e) {
120                 error = e;
121             }
122 
123         });
124 
125         while (true) {
126             // wait for SWT browser init
127             try {
128                 synchronized (LOCK) {
129                     if (error != null) {
130                         throw error;
131                     }
132                     if (isReady) {
133                         break;
134                     }
135                     LOCK.wait(1000);
136                 }
137             } catch (InterruptedException e) {
138                 DavGatewayTray.error(new BundleMessage("LOG_ERROR_WAITING_FOR_SWT_INIT"), e);
139                 Thread.currentThread().interrupt();
140             }
141         }
142 
143     }
144 
145     protected void dispose() {
146         Display.getDefault().asyncExec(() -> {
147             if (browser != null) {
148                 browser.dispose();
149             }
150             if (shell != null) {
151                 shell.dispose();
152             }
153         });
154     }
155 }