Statistics
| Revision:

gvsig-projects-pool / org.gvsig.online / trunk / org.gvsig.online / org.gvsig.online.swing / org.gvsig.online.swing.scribejava / src / main / java / org / gvsig / online / swing / scribejava / keycloak / UserIdentificationKeycloak.java @ 9514

History | View | Annotate | Download (10.7 KB)

1
/*
2
 * gvSIG. Desktop Geographic Information System.
3
 * 
4
 * Copyright (C) 2007-2020 gvSIG Association.
5
 * 
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 * 
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 * 
16
 * You should have received a copy of the GNU General Public License 
17
 * along with this program. If not, see <https://www.gnu.org/licenses/>. 
18
 * 
19
 * For any additional information, do not hesitate to contact us
20
 * at info AT gvsig.com, or visit our website www.gvsig.com.
21
 */
22
package org.gvsig.online.swing.scribejava.keycloak;
23

    
24
import org.gvsig.online.swing.scribejava.keycloak.callbacks.CallbackAuthorizationHandler;
25
import javax.swing.SwingUtilities;
26
import org.apache.commons.lang3.mutable.MutableBoolean;
27
import org.gvsig.online.lib.api.OnlineUserIdentificationRequester;
28

    
29
import com.github.scribejava.apis.KeycloakApi;
30
import com.github.scribejava.core.builder.ServiceBuilder;
31
import com.github.scribejava.core.model.OAuthRequest;
32
import com.github.scribejava.core.model.Response;
33
import com.github.scribejava.core.model.Verb;
34
import com.github.scribejava.core.oauth.OAuth20Service;
35
import java.awt.Desktop;
36
import java.awt.Frame;
37

    
38
import java.io.IOException;
39
import java.net.URI;
40
import java.net.URISyntaxException;
41
import java.util.UUID;
42
import java.util.concurrent.ExecutionException;
43
import javax.json.JsonObject;
44
import org.apache.commons.codec.net.URLCodec;
45
import org.apache.commons.lang.StringUtils;
46
import org.gvsig.json.Json;
47
import org.gvsig.online.swing.scribejava.keycloak.callbacks.CallbackLogoutHandler;
48
import org.gvsig.tools.library.impl.DefaultLibrariesInitializer;
49
import org.slf4j.Logger;
50
import org.slf4j.LoggerFactory;
51

    
52
/**
53
 *
54
 * @author gvSIG Team
55
 */
56
@SuppressWarnings("UseSpecificCatch")
57
public class UserIdentificationKeycloak
58
        implements OnlineUserIdentificationRequester {
59

    
60
    private static final Logger LOGGER = LoggerFactory.getLogger(UserIdentificationKeycloak.class);
61

    
62
    private static final String GVSIGDESKTOP_APIKEY = "gvsigdesktop";
63

    
64
    private String userId;
65
    private String authorization;
66
    private final UserIdentificationKeycloakConfig config;
67
    private final Object monitor = new Object();
68

    
69
    public UserIdentificationKeycloak(UserIdentificationKeycloakConfig config) {
70
        this.config = config;
71
        this.userId = null;
72
        this.authorization = null;
73
    }
74

    
75
    public UserIdentificationKeycloakConfig getConfig() {
76
        return this.config;
77
    }
78

    
79
    @Override
80
    public boolean requestIdentification() {
81
        try {
82
            if (!SwingUtilities.isEventDispatchThread()) {
83
                try {
84
                    MutableBoolean r = new MutableBoolean();
85
                    SwingUtilities.invokeAndWait(() -> {
86
                        r.setValue(requestIdentification());
87
                    });
88
                    return r.booleanValue();
89
                } catch (Exception ex) {
90
                    return false;
91
                }
92
            }
93

    
94
            String requestId = StringUtils.remove(UUID.randomUUID().toString(), "-");
95
            String authCallback = "http://localhost:" + this.config.getLocalPort() + "/auth_" + requestId;
96

    
97
            OAuth20Service service = createService(authCallback);
98
            
99
            logout(service, requestId);
100
            authorize(service, requestId);
101

    
102
            applicationToFront();
103
            return StringUtils.isNotBlank(this.authorization);
104
        } catch (Exception ex) {
105
            LOGGER.warn("Can't request authorization", ex);
106
            return false;
107
        }
108
    }
109

    
110
    private void applicationToFront() {
111
        try {
112
            java.awt.Window[] windows = Frame.getOwnerlessWindows();            
113
            if( windows != null ) {
114
                for (java.awt.Window window : windows) {
115
                    try {
116
                        window.toFront();
117
                    } catch(Exception ex) {
118
                        // Do nothing
119
                        LOGGER.debug("Can't bring to from "+window.toString());
120
                    }
121
                }
122
            }
123
        } catch(Exception e) {
124
            // Do nothing
125
            LOGGER.debug("Can't bring to from application");
126
        }
127
    }
128
    
129
    private OAuth20Service createService(String authCallback) {
130
        final String apiKey = GVSIGDESKTOP_APIKEY;
131
        final String baseUrl = this.config.getBaseurl();
132
        final String realm = this.config.getRealm();
133
        final String scope = "openid";
134

    
135
        final OAuth20Service service = new ServiceBuilder(apiKey)
136
                .apiSecretIsEmptyStringUnsafe()
137
                .defaultScope(scope)
138
                .callback(authCallback)
139
                .build(KeycloakApi.instance(baseUrl, realm));
140
        return service;
141
    }
142

    
143
    private void authorize(OAuth20Service service, String requestId) throws IOException, URISyntaxException {
144
        UserIdentificationKeycloakFactory factory = this.config.getFactory();
145
        String contextPath = "/auth_" + requestId;
146
        CallbackAuthorizationHandler callbackHandler = new CallbackAuthorizationHandler(this, service, contextPath);
147
//        LOGGER.info("authorize "+requestId);
148
        try {
149
            factory.addCallback(config, contextPath, callbackHandler);
150
            final String authorizationUrl = service.getAuthorizationUrl();
151
            Desktop.getDesktop().browse(new URI(authorizationUrl));
152
            this.waitForResponse();
153
        } catch(Exception e) {
154
            LOGGER.warn("Can't authorize",e);
155
            
156
        } finally {
157
//            LOGGER.info("authorize finally2 "+requestId);
158
            callbackHandler.remove();
159
//            LOGGER.info("authorize finally2 "+requestId);
160
        }
161
    }
162

    
163
    private void logout(OAuth20Service service, String requestId) throws URISyntaxException, IOException {
164
        UserIdentificationKeycloakFactory factory = this.config.getFactory();
165
        String contextPath = "/logout_" + requestId;
166
        CallbackLogoutHandler callbackHandler = new CallbackLogoutHandler(this, service, contextPath);
167
//        LOGGER.info("logout "+requestId);
168
        try {
169
            URLCodec urlcodec = new URLCodec();
170
            String redirect_uri = urlcodec.encode("http://localhost:" + config.getLocalPort() + "/logout_"+requestId);
171
            String realm = urlcodec.encode(config.getRealm());
172
            String client_id = urlcodec.encode(GVSIGDESKTOP_APIKEY);
173
            
174
            factory.addCallback(config, contextPath, callbackHandler);
175
            String logoutUrl = String.format(
176
                    "%s/auth/realms/%s/protocol/openid-connect/logout?post_logout_redirect_uri=%s&client_id=%s",
177
                    config.getBaseurl(),
178
                    realm,
179
                    redirect_uri,
180
                    client_id
181
            );
182
            
183
            Desktop.getDesktop().browse(new URI(logoutUrl));
184
            this.waitForResponse();
185
        } catch(Exception e) {
186
            LOGGER.warn("Can't logout",e);
187
            
188
        } finally {
189
//            LOGGER.info("logout finally1 "+requestId);
190
            callbackHandler.remove();
191
//            LOGGER.info("logout finally2 "+requestId);
192
        }
193
    }
194

    
195
    public JsonObject  userInfo(OAuth20Service service) throws InterruptedException, IOException, ExecutionException {
196
//        LOGGER.info("userInfo");
197
        final String protectedResourceUrl = config.getBaseurl() + "/auth/realms/" + config.getRealm() + "/protocol/openid-connect/userinfo";
198
        final OAuthRequest request = new OAuthRequest(Verb.GET, protectedResourceUrl);
199
        service.signRequest(this.getAuthorization(), request);
200
        try (final Response response = service.execute(request)) {
201
            if (response.getCode() == 200) {
202
                JsonObject userinfo = Json.createObject(response.getBody());
203
//                    System.out.println("userid: " + userinfo.getString("preferred_username", null);
204
//                    System.out.println("name: " + userinfo.getString("name", null));
205
//                    System.out.println("email: " + userinfo.getString("email", null));
206
//                    System.out.println("roles: " + userinfo.get("gvsigol_roles").toString());
207
//                    System.out.println("grupos: " + userinfo.get("groups").toString());
208
                return userinfo;
209
            }
210
        }
211
        return null;
212
    }
213

    
214
    public void waitForResponse() {
215
//        LOGGER.info("waitForTheResponse");
216
        synchronized (this.monitor) {
217
            try {
218
                this.monitor.wait(3 * 60 * 1000);
219
            } catch (InterruptedException ex) {
220

    
221
            }
222
        }
223
//        LOGGER.info("waitForTheResponse exit");
224
    }
225

    
226
    public void stopWaitingForResponse() {
227
//        LOGGER.info("stopWaitingForResponse");
228
        synchronized (this.monitor) {
229
            this.monitor.notifyAll();
230
        }
231
//        LOGGER.info("stopWaitingForResponse exit");
232
    }
233

    
234
    @Override
235
    public String getUserId() {
236
        return this.userId;
237
    }
238

    
239
    public void setUserId(String userId) {
240
        this.userId = userId;
241
    }
242

    
243
    @Override
244
    public String getAuthorization() {
245
        return this.authorization;
246
    }
247

    
248
    public void setAuthorization(String authorization) {
249
        this.authorization = authorization;
250
    }
251

    
252
    public static void main(String... args) throws Exception {
253
        new DefaultLibrariesInitializer().fullInitialize();
254

    
255
        UserIdentificationKeycloakFactory factory = new UserIdentificationKeycloakFactory();
256

    
257
        UserIdentificationKeycloakConfig conf = factory.create("https://devel.gvsigonline.com/gvsigonline");
258

    
259
        conf.setLocalPort(8888);
260
        conf.setBaseurl("https://keycloak.scolab.eu");
261
        conf.setRealm("joaquin");
262

    
263
        OnlineUserIdentificationRequester requester = conf.createUserIdentificationRequester();
264

    
265
        if (requester.requestIdentification()) {
266
            System.out.println("Identificacion concluida.");
267
            System.out.println("Usuario: " + requester.getUserId());
268
            System.out.println("Token  : " + requester.getAuthorization());
269
        } else {
270
            System.out.println("Identificacion fallida.");
271
        }
272

    
273
        Thread.sleep(4000);
274

    
275
        if (requester.requestIdentification()) {
276
            System.out.println("Identificacion concluida.");
277
            System.out.println("Usuario: " + requester.getUserId());
278
            System.out.println("Token  : " + requester.getAuthorization());
279
        } else {
280
            System.out.println("Identificacion fallida.");
281
        }
282

    
283
        factory.stopHttpServer(1);
284
    }
285
}