Ability to authenticate Oauth flow (#6326)

* Add keycloak token to oauth authenticate call

* fixup! Add keycloak token to oauth authenticate call

* fixup! Add keycloak token to oauth authenticate call

* Fix dashboard build

* fixup! Add keycloak token to oauth authenticate call

* fixup! Add keycloak token to oauth authenticate call

* Add security token for websocket url  (#6319)

* Add security token for websocket url

Signed-off-by: Vitalii Parfonov <vparfonov@redhat.com>

* Fix failed test (#6325)

Signed-off-by: Vitalii Parfonov <vparfonov@redhat.com>
6.19.x
Sergii Kabashniuk 2017-09-18 18:42:49 +03:00 committed by GitHub
parent 36f73bb4b4
commit d4f03cbc4a
19 changed files with 351 additions and 147 deletions

View File

@ -11,18 +11,10 @@
package org.eclipse.che.api.deploy;
import com.google.inject.AbstractModule;
import org.eclipse.che.api.environment.server.MachineLinksInjector;
import org.eclipse.che.api.workspace.server.WorkspaceServiceLinksInjector;
import org.eclipse.che.commons.auth.token.HeaderRequestTokenExtractor;
import org.eclipse.che.commons.auth.token.ChainedTokenExtractor;
import org.eclipse.che.commons.auth.token.RequestTokenExtractor;
import org.eclipse.che.inject.DynaModule;
import org.eclipse.che.multiuser.machine.authentication.server.AuthWsAgentHealthChecker;
import org.eclipse.che.multiuser.machine.authentication.server.MachineAuthLinksInjector;
import org.eclipse.che.multiuser.machine.authentication.server.MachineSessionInvalidator;
import org.eclipse.che.multiuser.machine.authentication.server.MachineTokenPermissionsFilter;
import org.eclipse.che.multiuser.machine.authentication.server.MachineTokenRegistry;
import org.eclipse.che.multiuser.machine.authentication.server.MachineTokenService;
import org.eclipse.che.multiuser.machine.authentication.server.WorkspaceServiceAuthLinksInjector;
import org.eclipse.che.multiuser.machine.authentication.server.interceptor.InterceptorModule;
/**
@ -32,18 +24,23 @@ import org.eclipse.che.multiuser.machine.authentication.server.interceptor.Inter
*/
@DynaModule
public class MachineAuthModule extends AbstractModule {
@Override
protected void configure() {
install(new InterceptorModule());
bind(MachineLinksInjector.class).to(MachineAuthLinksInjector.class);
bind(org.eclipse.che.api.agent.server.WsAgentHealthChecker.class)
.to(AuthWsAgentHealthChecker.class);
bind(MachineTokenPermissionsFilter.class);
bind(MachineTokenService.class);
bind(MachineTokenRegistry.class);
bind(MachineSessionInvalidator.class);
bind(RequestTokenExtractor.class).to(HeaderRequestTokenExtractor.class);
bind(WorkspaceServiceLinksInjector.class).to(WorkspaceServiceAuthLinksInjector.class);
.to(org.eclipse.che.multiuser.machine.authentication.server.AuthWsAgentHealthChecker.class);
bind(
org.eclipse.che.multiuser.machine.authentication.server.MachineTokenPermissionsFilter
.class);
bind(org.eclipse.che.multiuser.machine.authentication.server.MachineTokenService.class);
bind(org.eclipse.che.multiuser.machine.authentication.server.MachineTokenRegistry.class);
bind(org.eclipse.che.multiuser.machine.authentication.server.MachineSessionInvalidator.class);
bind(RequestTokenExtractor.class).to(ChainedTokenExtractor.class);
bind(WorkspaceServiceLinksInjector.class)
.to(
org.eclipse.che.multiuser.machine.authentication.server
.WorkspaceServiceAuthLinksInjector.class);
bind(org.eclipse.che.api.environment.server.MachineInstanceProvider.class)
.to(org.eclipse.che.plugin.docker.machine.AuthMachineProviderImpl.class);
}

View File

@ -23,6 +23,7 @@ import org.eclipse.che.ide.api.oauth.OAuth2Authenticator;
import org.eclipse.che.security.oauth.JsOAuthWindow;
import org.eclipse.che.security.oauth.OAuthCallback;
import org.eclipse.che.security.oauth.OAuthStatus;
import org.eclipse.che.security.oauth.SecurityTokenProvider;
/**
* Default implementation of authenticator, used when no provider-specific one is present.
@ -34,13 +35,18 @@ public class DefaultOAuthAuthenticatorImpl implements OAuth2Authenticator, OAuth
private final DialogFactory dialogFactory;
private final CoreLocalizationConstant localizationConstant;
private final SecurityTokenProvider provider;
private String authenticationUrl;
@Inject
public DefaultOAuthAuthenticatorImpl(
DialogFactory dialogFactory, CoreLocalizationConstant localizationConstant) {
DialogFactory dialogFactory,
CoreLocalizationConstant localizationConstant,
SecurityTokenProvider provider) {
this.dialogFactory = dialogFactory;
this.localizationConstant = localizationConstant;
this.provider = provider;
}
@Override
@ -96,7 +102,7 @@ public class DefaultOAuthAuthenticatorImpl implements OAuth2Authenticator, OAuth
private void showAuthWindow() {
JsOAuthWindow authWindow;
authWindow = new JsOAuthWindow(authenticationUrl, "error.url", 500, 980, this);
authWindow = new JsOAuthWindow(authenticationUrl, "error.url", 500, 980, this, provider);
authWindow.loginWithOAuth();
}
}

View File

@ -15,7 +15,10 @@ import static java.util.Collections.emptySet;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.ide.util.loging.Log;
import org.eclipse.che.security.oauth.SecurityTokenProvider;
/**
* Contain all routines related to a web socket connection initialization
@ -28,17 +31,20 @@ public class WebSocketInitializer {
private final WebSocketPropertyManager propertyManager;
private final WebSocketActionManager actionManager;
private final UrlResolver urlResolver;
private SecurityTokenProvider securityTokenProvider;
@Inject
public WebSocketInitializer(
WebSocketConnectionManager connectionManager,
WebSocketPropertyManager propertyManager,
WebSocketActionManager actionManager,
UrlResolver urlResolver) {
UrlResolver urlResolver,
SecurityTokenProvider securityTokenProvider) {
this.connectionManager = connectionManager;
this.propertyManager = propertyManager;
this.actionManager = actionManager;
this.urlResolver = urlResolver;
this.securityTokenProvider = securityTokenProvider;
}
/**
@ -61,16 +67,27 @@ public class WebSocketInitializer {
* @param initActions actions to be performed each time the connection is established
*/
public void initialize(String endpointId, String url, Set<Runnable> initActions) {
Log.debug(getClass(), "Initializing with url: " + url);
securityTokenProvider
.getSecurityToken()
.then(
new Operation<String>() {
@Override
public void apply(String token) throws OperationException {
String separator = url.contains("?") ? "&" : "?";
final String secureUrl = url + separator + "token=" + token;
urlResolver.setMapping(endpointId, url);
Log.debug(getClass(), "Initializing with secureUrl: " + secureUrl);
propertyManager.initializeConnection(url);
urlResolver.setMapping(endpointId, secureUrl);
actionManager.setOnEstablishActions(url, initActions);
propertyManager.initializeConnection(secureUrl);
connectionManager.initializeConnection(url);
connectionManager.establishConnection(url);
actionManager.setOnEstablishActions(secureUrl, initActions);
connectionManager.initializeConnection(secureUrl);
connectionManager.establishConnection(secureUrl);
}
});
}
/**

View File

@ -11,6 +11,10 @@
package org.eclipse.che.security.oauth;
import com.google.gwt.user.client.Window;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.util.loging.Log;
/** @author Vladislav Zhukovskii */
public class JsOAuthWindow {
@ -19,16 +23,23 @@ public class JsOAuthWindow {
private OAuthStatus authStatus;
private int popupHeight;
private int popupWidth;
private SecurityTokenProvider provider;
private int clientHeight;
private int clientWidth;
private OAuthCallback callback;
public JsOAuthWindow(
String authUrl, String errUrl, int popupHeight, int popupWidth, OAuthCallback callback) {
String authUrl,
String errUrl,
int popupHeight,
int popupWidth,
OAuthCallback callback,
SecurityTokenProvider provider) {
this.authUrl = authUrl;
this.errUrl = errUrl;
this.popupHeight = popupHeight;
this.popupWidth = popupWidth;
this.provider = provider;
this.clientHeight = Window.getClientHeight();
this.clientWidth = Window.getClientWidth();
this.callback = callback;
@ -46,7 +57,25 @@ public class JsOAuthWindow {
}
public void loginWithOAuth() {
loginWithOAuth(authUrl, errUrl, popupHeight, popupWidth, clientHeight, clientWidth);
provider
.getSecurityToken()
.then(
new Operation<String>() {
@Override
public void apply(String arg) throws OperationException {
if (arg != null) {
authUrl = authUrl + "&token=" + arg;
}
loginWithOAuth(authUrl, errUrl, popupHeight, popupWidth, clientHeight, clientWidth);
}
})
.catchError(
new Operation<PromiseError>() {
@Override
public void apply(PromiseError arg) throws OperationException {
Log.error(getClass(), arg);
}
});
}
private native void loginWithOAuth(

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2012-2017 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.security.oauth;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.api.promises.client.PromiseProvider;
/** Provider of tokens that needed to authenticate requests. */
@Singleton
public class SecurityTokenProvider {
@Inject PromiseProvider promiseProvider;
public Promise<String> getSecurityToken() {
return promiseProvider.resolve(null);
}
}

View File

@ -16,6 +16,7 @@
<inherits name="org.eclipse.che.ide.useragents"/>
<inherits name="elemental.Elemental"/>
<inherits name="com.google.gwt.json.JSON"/>
<inherits name="org.eclipse.che.api.promises.Promises"/>
<source path=""/>

View File

@ -13,10 +13,16 @@ package org.eclipse.che.ide.websocket.impl;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.security.oauth.SecurityTokenProvider;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
@ -32,40 +38,53 @@ public class WebSocketInitializerTest {
@Mock private WebSocketPropertyManager propertyManager;
@Mock private UrlResolver urlResolver;
@Mock private WebSocketActionManager webSocketActionManager;
@Mock private SecurityTokenProvider securityTokenProvider;
@Mock private Promise promise;
@Captor private ArgumentCaptor<Operation<String>> operation;
@InjectMocks private WebSocketInitializer initializer;
@Before
public void setUp() throws Exception {}
public void setUp() throws Exception {
when(securityTokenProvider.getSecurityToken()).thenReturn(promise);
}
@After
public void tearDown() throws Exception {}
@Test
public void shouldSetUrlMappingOnInitialize() {
initializer.initialize("id", "url");
public void shouldSetUrlMappingOnInitialize() throws OperationException {
verify(urlResolver).setMapping("id", "url");
initializer.initialize("id", "http://test.com");
verify(promise).then(operation.capture());
operation.getValue().apply("token");
verify(securityTokenProvider).getSecurityToken();
verify(urlResolver).setMapping("id", "http://test.com?token=token");
}
@Test
public void shouldRunConnectionManagerInitializeConnectionOnInitialize() {
initializer.initialize("id", "url");
verify(connectionManager).initializeConnection("url");
public void shouldRunConnectionManagerInitializeConnectionOnInitialize()
throws OperationException {
initializer.initialize("id", "http://test.com");
verify(promise).then(operation.capture());
operation.getValue().apply("token");
verify(securityTokenProvider).getSecurityToken();
verify(connectionManager).initializeConnection("http://test.com?token=token");
}
@Test
public void shouldRunPropertyManagerInitializeConnectionOnInitialize() {
public void shouldRunPropertyManagerInitializeConnectionOnInitialize() throws OperationException {
initializer.initialize("id", "url");
verify(propertyManager).initializeConnection("url");
verify(promise).then(operation.capture());
operation.getValue().apply("token");
verify(propertyManager).initializeConnection("url?token=token");
}
@Test
public void shouldRunEstablishConnectionOnInitialize() {
public void shouldRunEstablishConnectionOnInitialize() throws OperationException {
initializer.initialize("id", "url");
verify(connectionManager).establishConnection("url");
verify(promise).then(operation.capture());
operation.getValue().apply("token");
verify(connectionManager).establishConnection("url?token=token");
}
@Test

View File

@ -31,6 +31,10 @@
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-commons-gwt</artifactId>

View File

@ -38,6 +38,7 @@ public final class Keycloak extends JavaScriptObject {
console.log('[Keycloak] Failed to initialize Keycloak');
reject();
});
console.log('[Keycloak] Initializing complete');
} catch (ex) {
console.log('[Keycloak] Failed to initialize Keycloak with exception: ', ex);
reject();

View File

@ -22,16 +22,16 @@ import org.eclipse.che.ide.util.loging.Log;
/** KeycloakAsyncRequests */
public class KeycloakAsyncRequest extends AsyncRequest {
private Promise<Keycloak> keycloakPromise;
private KeycloakProvider keycloakProvider;
public KeycloakAsyncRequest(
Promise<Keycloak> keycloakPromise, RequestBuilder.Method method, String url, boolean async) {
KeycloakProvider keycloakProvider, RequestBuilder.Method method, String url, boolean async) {
super(method, url, async);
this.keycloakPromise = keycloakPromise;
this.keycloakProvider = keycloakProvider;
}
private void addAuthorizationHeader(Keycloak keycloak) {
header(HTTPHeader.AUTHORIZATION, "Bearer " + keycloak.getToken());
private void addAuthorizationHeader(String keycloakToken) {
header(HTTPHeader.AUTHORIZATION, "Bearer " + keycloakToken);
}
private static interface Sender<R> {
@ -39,47 +39,21 @@ public class KeycloakAsyncRequest extends AsyncRequest {
}
private <R> Promise<R> doAfterKeycloakInitAndUpdate(Sender<R> sender) {
return keycloakPromise.thenPromise(
new Function<Keycloak, Promise<R>>() {
@Override
public Promise<R> apply(Keycloak keycloak) {
Log.debug(getClass(), "Keycloak initialized with token: ", keycloak.getToken());
try {
return keycloak
.updateToken(5)
.thenPromise(
new Function<Boolean, Promise<R>>() {
@Override
public Promise<R> apply(Boolean refreshed) {
if (refreshed) {
Log.debug(
getClass(),
"Keycloak updated token before sending the request `",
KeycloakAsyncRequest.this.requestBuilder.getUrl(),
"`. New token is : ",
keycloak.getToken());
} else {
Log.debug(
getClass(),
"Keycloak didn't need to update token before sending the request `",
KeycloakAsyncRequest.this.requestBuilder.getUrl(),
"`");
}
addAuthorizationHeader(keycloak);
try {
return sender.doSend();
} catch (Throwable t) {
Log.error(getClass(), t);
throw t;
}
}
});
} catch (Throwable t) {
Log.error(getClass(), t);
throw t;
}
}
});
return keycloakProvider
.getUpdatedToken(5)
.thenPromise(
new Function<String, Promise<R>>() {
@Override
public Promise<R> apply(String keycloakToken) {
addAuthorizationHeader(keycloakToken);
try {
return sender.doSend();
} catch (Throwable t) {
Log.error(getClass(), t);
throw t;
}
}
});
}
@Override

View File

@ -10,30 +10,18 @@
*/
package org.eclipse.che.multiuser.keycloak.ide;
import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.AUTH_SERVER_URL_SETTING;
import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.CLIENT_ID_SETTING;
import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.REALM_SETTING;
import com.google.gwt.core.client.Callback;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.ScriptInjector;
import com.google.gwt.http.client.RequestBuilder;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.web.bindery.event.shared.EventBus;
import java.util.List;
import java.util.Map;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.api.promises.client.callback.CallbackPromiseHelper;
import org.eclipse.che.ide.MimeType;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.dto.DtoFactory;
import org.eclipse.che.ide.json.JsonHelper;
import org.eclipse.che.ide.rest.AsyncRequest;
import org.eclipse.che.ide.rest.HTTPHeader;
import org.eclipse.che.ide.util.loging.Log;
import org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants;
import org.eclipse.che.multiuser.machine.authentication.ide.MachineAsyncRequestFactory;
import org.eclipse.che.multiuser.machine.authentication.ide.MachineTokenServiceClient;
@ -42,50 +30,18 @@ import org.eclipse.che.multiuser.machine.authentication.ide.MachineTokenServiceC
public class KeycloakAsyncRequestFactory extends MachineAsyncRequestFactory {
private final DtoFactory dtoFactory;
private Promise<Keycloak> keycloak;
private KeycloakProvider keycloakProvider;
@Inject
public KeycloakAsyncRequestFactory(
KeycloakProvider keycloakProvider,
DtoFactory dtoFactory,
Provider<MachineTokenServiceClient> machineTokenServiceProvider,
AppContext appContext,
EventBus eventBus) {
super(dtoFactory, machineTokenServiceProvider, appContext, eventBus);
this.dtoFactory = dtoFactory;
String keycloakSettings =
getKeycloakSettings(KeycloakConstants.getEndpoint(appContext.getMasterEndpoint()));
Map<String, String> settings = JsonHelper.toMap(keycloakSettings);
Log.info(getClass(), "Keycloak settings: ", settings);
keycloak =
CallbackPromiseHelper.createFromCallback(
new CallbackPromiseHelper.Call<Void, Throwable>() {
@Override
public void makeCall(final Callback<Void, Throwable> callback) {
ScriptInjector.fromUrl(
settings.get(AUTH_SERVER_URL_SETTING) + "/js/keycloak.js")
.setCallback(
new Callback<Void, Exception>() {
@Override
public void onSuccess(Void result) {
callback.onSuccess(null);
}
@Override
public void onFailure(Exception reason) {
callback.onFailure(reason);
}
})
.setWindow(getWindow())
.inject();
}
})
.thenPromise(
(v) ->
Keycloak.init(
settings.get(AUTH_SERVER_URL_SETTING),
settings.get(REALM_SETTING),
settings.get(CLIENT_ID_SETTING)));
this.keycloakProvider = keycloakProvider;
}
@Override
@ -93,7 +49,7 @@ public class KeycloakAsyncRequestFactory extends MachineAsyncRequestFactory {
RequestBuilder.Method method, String url, Object dtoBody, boolean async) {
AsyncRequest request = super.doCreateRequest(method, url, dtoBody, async);
if (!isWsAgentRequest(url)) {
AsyncRequest asyncRequest = new KeycloakAsyncRequest(keycloak, method, url, async);
AsyncRequest asyncRequest = new KeycloakAsyncRequest(keycloakProvider, method, url, async);
if (dtoBody != null) {
if (dtoBody instanceof List<?>) {
asyncRequest.data(dtoFactory.toJson((List<?>) dtoBody));

View File

@ -0,0 +1,125 @@
/*
* Copyright (c) 2012-2017 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.keycloak.ide;
import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.AUTH_SERVER_URL_SETTING;
import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.CLIENT_ID_SETTING;
import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.REALM_SETTING;
import com.google.gwt.core.client.Callback;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.ScriptInjector;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.util.Map;
import org.eclipse.che.api.promises.client.Function;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.api.promises.client.PromiseProvider;
import org.eclipse.che.api.promises.client.callback.CallbackPromiseHelper;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.json.JsonHelper;
import org.eclipse.che.ide.util.loging.Log;
import org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants;
/** KeycloakProvider */
@Singleton
public class KeycloakProvider {
private AppContext appContext;
private boolean keycloakDisabled = false;
private Promise<Keycloak> keycloak;
@Inject
public KeycloakProvider(AppContext appContext, PromiseProvider promiseProvider) {
this.appContext = appContext;
String keycloakSettings =
getKeycloakSettings(KeycloakConstants.getEndpoint(appContext.getMasterEndpoint()));
Map<String, String> settings = JsonHelper.toMap(keycloakSettings);
Log.info(getClass(), "Keycloak settings: ", settings);
keycloak =
CallbackPromiseHelper.createFromCallback(
new CallbackPromiseHelper.Call<Void, Throwable>() {
@Override
public void makeCall(final Callback<Void, Throwable> callback) {
ScriptInjector.fromUrl(
settings.get(AUTH_SERVER_URL_SETTING) + "/js/keycloak.js")
.setCallback(
new Callback<Void, Exception>() {
@Override
public void onSuccess(Void result) {
callback.onSuccess(null);
}
@Override
public void onFailure(Exception reason) {
callback.onFailure(reason);
}
})
.setWindow(getWindow())
.inject();
}
})
.thenPromise(
(v) ->
Keycloak.init(
settings.get(AUTH_SERVER_URL_SETTING),
settings.get(REALM_SETTING),
settings.get(CLIENT_ID_SETTING)));
Log.info(getClass(), "Keycloak init complete: ", this);
}
public static native String getKeycloakSettings(String keycloakSettingsEndpoint) /*-{
var myReq = new XMLHttpRequest();
myReq.open('GET', '' + keycloakSettingsEndpoint, false);
myReq.send(null);
return myReq.responseText;
}-*/;
public static native JavaScriptObject getWindow() /*-{
return $wnd;
}-*/;
public Promise<Keycloak> getKeycloak() {
return keycloak;
}
public Promise<String> getUpdatedToken(int minValidity) {
return keycloak.thenPromise(
new Function<Keycloak, Promise<String>>() {
@Override
public Promise<String> apply(Keycloak keycloak) {
Log.debug(getClass(), "Keycloak initialized with token: ", keycloak.getToken());
try {
return keycloak
.updateToken(minValidity)
.then(
new Function<Boolean, String>() {
@Override
public String apply(Boolean refreshed) {
if (refreshed) {
Log.debug(
getClass(),
"Keycloak updated token. New token is : ",
keycloak.getToken());
} else {
Log.debug(getClass(), "Keycloak didn't need to update token.");
}
return keycloak.getToken();
}
});
} catch (Throwable t) {
Log.error(getClass(), t);
throw t;
}
}
});
}
}

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2012-2017 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.multiuser.keycloak.ide;
import javax.inject.Inject;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.security.oauth.SecurityTokenProvider;
public class KeycloakSecurityTokenProvider extends SecurityTokenProvider {
@Inject KeycloakProvider keycloakProvider;
@Override
public Promise<String> getSecurityToken() {
return keycloakProvider.getUpdatedToken(5);
}
}

View File

@ -13,6 +13,9 @@ package org.eclipse.che.multiuser.keycloak.ide.inject;
import com.google.gwt.inject.client.AbstractGinModule;
import org.eclipse.che.ide.api.extension.ExtensionGinModule;
import org.eclipse.che.ide.rest.AsyncRequestFactory;
import org.eclipse.che.multiuser.keycloak.ide.KeycloakProvider;
import org.eclipse.che.multiuser.keycloak.ide.KeycloakSecurityTokenProvider;
import org.eclipse.che.security.oauth.SecurityTokenProvider;
/** KeycloakAuthGinModule */
@ExtensionGinModule
@ -20,7 +23,9 @@ public class KeycloakAuthGinModule extends AbstractGinModule {
@Override
public void configure() {
bind(KeycloakProvider.class).asEagerSingleton();
bind(AsyncRequestFactory.class)
.to(org.eclipse.che.multiuser.keycloak.ide.KeycloakAsyncRequestFactory.class);
bind(SecurityTokenProvider.class).to(KeycloakSecurityTokenProvider.class);
}
}

View File

@ -22,10 +22,10 @@ public class KeycloakServletModule extends ServletModule {
// Not contains '/websocket', /docs/ (for swagger) and not ends with '/ws' or '/eventbus' or '/settings/' or '/api/system/state' or '/api/stack/[^/]+/icon/'
filterRegex(
"^(?!.*(/websocket/?|/docs/))(?!.*(/ws/?|/eventbus/?|/settings/?|/api/system/state/?|/api/stack/[^/]+/icon/?)$).*")
"^(?!.*(/websocket/?|/docs/))(?!.*(/ws/?|/eventbus/?|/settings/?|/api/oauth/callback/?|/api/system/state/?|/api/stack/[^/]+/icon/?)$).*")
.through(KeycloakAuthenticationFilter.class);
filterRegex(
"^(?!.*(/websocket/?|/docs/))(?!.*(/ws/?|/eventbus/?|/settings/?|/api/system/state/?|/api/stack/[^/]+/icon/?)$).*")
"^(?!.*(/websocket/?|/docs/))(?!.*(/ws/?|/eventbus/?|/settings/?|/api/oauth/callback/?|/api/system/state/?|/api/stack/[^/]+/icon/?)$).*")
.through(KeycloakEnvironmentInitalizationFilter.class);
}
}

View File

@ -29,6 +29,7 @@ import org.eclipse.che.plugin.ssh.key.client.SshKeyUploader;
import org.eclipse.che.security.oauth.JsOAuthWindow;
import org.eclipse.che.security.oauth.OAuthCallback;
import org.eclipse.che.security.oauth.OAuthStatus;
import org.eclipse.che.security.oauth.SecurityTokenProvider;
/**
* Uploads SSH keys for github.com.
@ -45,6 +46,7 @@ public class GitHubSshKeyUploader implements SshKeyUploader, OAuthCallback {
private final ProductInfoDataProvider productInfoDataProvider;
private final DialogFactory dialogFactory;
private final AppContext appContext;
private final SecurityTokenProvider securityTokenProvider;
private AsyncCallback<Void> callback;
private String userId;
@ -56,7 +58,8 @@ public class GitHubSshKeyUploader implements SshKeyUploader, OAuthCallback {
NotificationManager notificationManager,
ProductInfoDataProvider productInfoDataProvider,
DialogFactory dialogFactory,
AppContext appContext) {
AppContext appContext,
SecurityTokenProvider securityTokenProvider) {
this.gitHubService = gitHubService;
this.baseUrl = appContext.getMasterEndpoint();
this.constant = constant;
@ -64,6 +67,7 @@ public class GitHubSshKeyUploader implements SshKeyUploader, OAuthCallback {
this.productInfoDataProvider = productInfoDataProvider;
this.dialogFactory = dialogFactory;
this.appContext = appContext;
this.securityTokenProvider = securityTokenProvider;
}
/** {@inheritDoc} */
@ -124,7 +128,8 @@ public class GitHubSshKeyUploader implements SshKeyUploader, OAuthCallback {
+ Window.Location.getHost()
+ "/ws/"
+ appContext.getWorkspace().getConfig().getName();
JsOAuthWindow authWindow = new JsOAuthWindow(authUrl, "error.url", 500, 980, this);
JsOAuthWindow authWindow =
new JsOAuthWindow(authUrl, "error.url", 500, 980, this, securityTokenProvider);
authWindow.loginWithOAuth();
}

View File

@ -38,6 +38,7 @@ import org.eclipse.che.plugin.ssh.key.client.manage.SshKeyManagerPresenter;
import org.eclipse.che.security.oauth.JsOAuthWindow;
import org.eclipse.che.security.oauth.OAuthCallback;
import org.eclipse.che.security.oauth.OAuthStatus;
import org.eclipse.che.security.oauth.SecurityTokenProvider;
/** @author Roman Nikitenko */
public class GitHubAuthenticatorImpl
@ -55,6 +56,7 @@ public class GitHubAuthenticatorImpl
private final GitHubLocalizationConstant locale;
private final String baseUrl;
private final AppContext appContext;
private final SecurityTokenProvider securityTokenPærovider;
private String authenticationUrl;
@Inject
@ -65,10 +67,12 @@ public class GitHubAuthenticatorImpl
DialogFactory dialogFactory,
GitHubLocalizationConstant locale,
NotificationManager notificationManager,
AppContext appContext) {
AppContext appContext,
SecurityTokenProvider securityTokenPærovider) {
this.registry = registry;
this.sshServiceClient = sshServiceClient;
this.view = view;
this.securityTokenPærovider = securityTokenPærovider;
this.view.setDelegate(this);
this.locale = locale;
this.baseUrl = appContext.getMasterEndpoint();
@ -125,9 +129,11 @@ public class GitHubAuthenticatorImpl
private void showAuthWindow() {
JsOAuthWindow authWindow;
if (authenticationUrl == null) {
authWindow = new JsOAuthWindow(getAuthUrl(), "error.url", 500, 980, this);
authWindow =
new JsOAuthWindow(getAuthUrl(), "error.url", 500, 980, this, securityTokenPærovider);
} else {
authWindow = new JsOAuthWindow(authenticationUrl, "error.url", 500, 980, this);
authWindow =
new JsOAuthWindow(authenticationUrl, "error.url", 500, 980, this, securityTokenPærovider);
}
authWindow.loginWithOAuth();
}

View File

@ -48,6 +48,7 @@ import org.eclipse.che.plugin.pullrequest.client.vcs.hosting.VcsHostingService;
import org.eclipse.che.plugin.pullrequest.shared.dto.HostUser;
import org.eclipse.che.plugin.pullrequest.shared.dto.PullRequest;
import org.eclipse.che.plugin.pullrequest.shared.dto.Repository;
import org.eclipse.che.security.oauth.SecurityTokenProvider;
/**
* {@link VcsHostingService} implementation for GitHub.
@ -74,6 +75,7 @@ public class GitHubHostingService implements VcsHostingService {
private final GitHubClientService gitHubClientService;
private final HostingServiceTemplates templates;
private final String baseUrl;
private final SecurityTokenProvider securityTokenProvider;
@Inject
public GitHubHostingService(
@ -81,12 +83,14 @@ public class GitHubHostingService implements VcsHostingService {
@NotNull final AppContext appContext,
@NotNull final DtoFactory dtoFactory,
@NotNull final GitHubClientService gitHubClientService,
@NotNull final GitHubTemplates templates) {
@NotNull final GitHubTemplates templates,
SecurityTokenProvider securityTokenProvider) {
this.appContext = appContext;
this.dtoFactory = dtoFactory;
this.gitHubClientService = gitHubClientService;
this.templates = templates;
this.baseUrl = baseUrl;
this.securityTokenProvider = securityTokenProvider;
}
@Override
@ -512,7 +516,7 @@ public class GitHubHostingService implements VcsHostingService {
+ Window.Location.getHost()
+ "/ws/"
+ workspace.getConfig().getName();
return ServiceUtil.performWindowAuth(this, authUrl);
return ServiceUtil.performWindowAuth(this, authUrl, securityTokenProvider);
}
@Override

View File

@ -22,6 +22,7 @@ import org.eclipse.che.plugin.pullrequest.shared.dto.HostUser;
import org.eclipse.che.security.oauth.JsOAuthWindow;
import org.eclipse.che.security.oauth.OAuthCallback;
import org.eclipse.che.security.oauth.OAuthStatus;
import org.eclipse.che.security.oauth.SecurityTokenProvider;
/**
* Utils for {@link VcsHostingService} implementations.
@ -38,7 +39,9 @@ public final class ServiceUtil {
* @return the promise which resolves authorized user or rejects with an error
*/
public static Promise<HostUser> performWindowAuth(
final VcsHostingService service, final String authUrl) {
final VcsHostingService service,
final String authUrl,
final SecurityTokenProvider securityTokenProvider) {
final Executor.ExecutorBody<HostUser> exBody =
new Executor.ExecutorBody<HostUser>() {
@Override
@ -69,7 +72,8 @@ public final class ServiceUtil {
}
});
}
})
},
securityTokenProvider)
.loginWithOAuth();
}
};