diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebPropertyInfo.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebPropertyInfo.java index 54f682e3ac..0cc54dabd2 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebPropertyInfo.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebPropertyInfo.java @@ -123,7 +123,7 @@ public class WebPropertyInfo { public Object getValue() throws DBException { Object value = propertySource == null ? null : propertySource.getPropertyValue(session.getProgressMonitor(), property.getId()); if (property instanceof ObjectPropertyDescriptor) { - ObjectPropertyDescriptor opd = (ObjectPropertyDescriptor)property; + ObjectPropertyDescriptor opd = (ObjectPropertyDescriptor) property; if (!showProtected && opd.isPassword() || opd.isHidden()) { if (value == null || value.toString().isEmpty()) { return ""; diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebAuthInfo.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebAuthInfo.java index 445b35b173..eefd83a59d 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebAuthInfo.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebAuthInfo.java @@ -80,7 +80,7 @@ public class WebAuthInfo implements SMSessionPrincipal { @Property public WebUserOriginInfo getOrigin() { - return new WebUserOriginInfo(session, user, authProvider, true); + return new WebUserOriginInfo(session, user, authProvider); } @Property diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUserOriginInfo.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUserOriginInfo.java index 25202403dc..7b6e275547 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUserOriginInfo.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUserOriginInfo.java @@ -20,7 +20,6 @@ import io.cloudbeaver.DBWebException; import io.cloudbeaver.auth.SMAuthProviderExternal; import io.cloudbeaver.model.WebObjectOrigin; import io.cloudbeaver.model.WebPropertyInfo; -import io.cloudbeaver.model.session.WebAuthInfo; import io.cloudbeaver.model.session.WebSession; import io.cloudbeaver.registry.WebAuthProviderDescriptor; import io.cloudbeaver.utils.WebCommonUtils; @@ -28,13 +27,12 @@ import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; -import org.jkiss.dbeaver.model.DBPObject; import org.jkiss.dbeaver.model.auth.SMAuthProvider; -import org.jkiss.dbeaver.model.auth.SMSession; +import org.jkiss.dbeaver.model.impl.PropertyDescriptor; import org.jkiss.dbeaver.model.meta.Property; +import org.jkiss.dbeaver.runtime.properties.PropertySourceMap; +import org.jkiss.utils.CommonUtils; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; import java.util.Collections; import java.util.Map; @@ -45,23 +43,21 @@ public class WebUserOriginInfo implements WebObjectOrigin { private static final Log log = Log.getLog(WebUserOriginInfo.class); - private final WebSession session; - private final WebUser user; + protected final WebSession session; + protected final WebUser user; @NotNull - private final WebAuthProviderDescriptor authProvider; - private boolean selfIdentity; + protected final WebAuthProviderDescriptor authProviderDescriptor; - public WebUserOriginInfo(WebSession session, WebUser user, @NotNull WebAuthProviderDescriptor authProvider, boolean selfIdentity) { + public WebUserOriginInfo(WebSession session, WebUser user, @NotNull WebAuthProviderDescriptor authProvider) { this.session = session; this.user = user; - this.authProvider = authProvider; - this.selfIdentity = selfIdentity; + this.authProviderDescriptor = authProvider; } @NotNull @Override public String getType() { - return authProvider.getId(); + return authProviderDescriptor.getId(); } @Nullable @@ -73,13 +69,13 @@ public class WebUserOriginInfo implements WebObjectOrigin { @NotNull @Override public String getDisplayName() { - return authProvider.getLabel(); + return authProviderDescriptor.getLabel(); } @Nullable @Override public String getIcon() { - return WebCommonUtils.makeIconId(authProvider.getIcon()); + return WebCommonUtils.makeIconId(authProviderDescriptor.getIcon()); } @NotNull @@ -95,25 +91,12 @@ public class WebUserOriginInfo implements WebObjectOrigin { return new WebPropertyInfo[0]; } try { - WebAuthInfo authInfo = session.getAuthInfo(authProvider.getId()); - if (authInfo == null) { - throw new DBException("Session not authorized in auth provider '" + authProvider.getId() + "'"); - } - SMSession authSession = authInfo.getAuthSession(); - SMAuthProvider authProvider = this.authProvider.getInstance(); - if (authSession != null && authProvider instanceof SMAuthProviderExternal) { - if (!isValidSessionType(authSession, authProvider)) { - return new WebPropertyInfo[0]; - } - DBPObject userDetails = ((SMAuthProviderExternal) authProvider).getUserDetails( - session.getProgressMonitor(), - session, - authSession, - user, - selfIdentity); - if (userDetails != null) { - return WebCommonUtils.getObjectProperties(session, userDetails); - } + SMAuthProvider authProvider = this.authProviderDescriptor.getInstance(); + if (authProvider instanceof SMAuthProviderExternal) { + // read user's info from credentials, previously we tried to read data from external service using + // SMAuthProviderExternal#getUserDetails + var creds = loadCredentials(); + return mapCredsToProperties(session, creds); } } catch (Exception e) { log.error(e); @@ -121,16 +104,32 @@ public class WebUserOriginInfo implements WebObjectOrigin { return new WebPropertyInfo[0]; } - private static boolean isValidSessionType(SMSession authSession, SMAuthProvider authProvider) { - Type providerSuperClass = authProvider.getClass().getGenericSuperclass(); - if (providerSuperClass instanceof ParameterizedType) { - Type[] typeArguments = ((ParameterizedType) providerSuperClass).getActualTypeArguments(); - if (typeArguments.length == 1 && typeArguments[0] instanceof Class) { - // Wrong session type for this auth provider - return ((Class) typeArguments[0]).isInstance(authSession); - } + protected Map loadCredentials() throws DBException { + return session.getSecurityController().getCurrentUserCredentials(this.authProviderDescriptor.getId()); + } + + private static WebPropertyInfo[] mapCredsToProperties( + WebSession session, Map creds + ) { + if (CommonUtils.isEmpty(creds)) { + return new WebPropertyInfo[0]; } - return true; + var propSource = new PropertySourceMap(creds); + return creds.entrySet() + .stream() + .map(entry -> new PropertyDescriptor( + null, + entry.getKey(), + entry.getKey(), + null, + true, + entry.getValue().getClass(), + null, + new Object[0] + ) + ) + .map(propDescriptor -> new WebPropertyInfo(session, propDescriptor, propSource)) + .toArray(WebPropertyInfo[]::new); } } diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminOriginInfo.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminOriginInfo.java new file mode 100644 index 0000000000..9ed3c2086d --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminOriginInfo.java @@ -0,0 +1,41 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2023 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.cloudbeaver.service.admin; + +import io.cloudbeaver.model.session.WebSession; +import io.cloudbeaver.model.user.WebUser; +import io.cloudbeaver.model.user.WebUserOriginInfo; +import io.cloudbeaver.registry.WebAuthProviderDescriptor; +import org.jkiss.code.NotNull; +import org.jkiss.dbeaver.DBException; + +import java.util.Map; + +public class AdminOriginInfo extends WebUserOriginInfo { + public AdminOriginInfo( + WebSession session, + WebUser user, + @NotNull WebAuthProviderDescriptor authProvider + ) { + super(session, user, authProvider); + } + + @Override + protected Map loadCredentials() throws DBException { + return session.getAdminSecurityController().getUserCredentials(user.getUserId(), authProviderDescriptor.getId()); + } +} diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminUserInfo.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminUserInfo.java index dae29c9097..d047b3dfee 100644 --- a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminUserInfo.java +++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminUserInfo.java @@ -94,16 +94,16 @@ public class AdminUserInfo { @Property public WebUserOriginInfo[] getOrigins() throws DBWebException { - List result = new ArrayList<>(); + List result = new ArrayList<>(); for (String provider : getUserLinkedProviders()) { WebAuthProviderDescriptor authProvider = WebAuthProviderRegistry.getInstance().getAuthProvider(provider); if (authProvider == null) { log.error("Auth provider '" + provider + "' not found"); } else { - result.add(new WebUserOriginInfo(session, user, authProvider, false)); + result.add(new AdminOriginInfo(session, user, authProvider)); } } - return result.toArray(new WebUserOriginInfo[0]); + return result.toArray(new AdminOriginInfo[0]); } @Property diff --git a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/WebUserAuthToken.java b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/WebUserAuthToken.java index 5e15c37801..bc2b9c042b 100644 --- a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/WebUserAuthToken.java +++ b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/WebUserAuthToken.java @@ -71,7 +71,7 @@ public class WebUserAuthToken { @NotNull public WebUserOriginInfo getOrigin() { - return new WebUserOriginInfo(session, user, authInfo.getAuthProviderDescriptor(), true); + return new WebUserOriginInfo(session, user, authInfo.getAuthProviderDescriptor()); } } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/OriginInfoPanel.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/OriginInfoPanel.tsx index 45556cbf99..c91e6976ad 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/OriginInfoPanel.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/OriginInfoPanel.tsx @@ -9,11 +9,11 @@ import { observer } from 'mobx-react-lite'; import styled from 'reshadow'; -import { UserInfoResource, UsersResource } from '@cloudbeaver/core-authentication'; +import { UsersResource } from '@cloudbeaver/core-authentication'; import { TextPlaceholder, Loader, ExceptionMessage, BASE_CONTAINERS_STYLES, ColoredContainer, ObjectPropertyInfoForm, Group, useAutoLoad, useObjectRef, IAutoLoadable, useTranslate, useStyles } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import type { AdminUserInfo, ObjectPropertyInfo } from '@cloudbeaver/core-sdk'; -import { AuthenticationProvider, TabContainerPanelComponent, useTab, useTabState } from '@cloudbeaver/core-ui'; +import { TabContainerPanelComponent, useTab, useTabState } from '@cloudbeaver/core-ui'; import { getOriginTabId } from './getOriginTabId'; import type { IUserFormProps } from './UserFormService'; @@ -38,7 +38,6 @@ export const OriginInfoPanel: TabContainerPanelComponent = obser const style = useStyles(BASE_CONTAINERS_STYLES); const translate = useTranslate(); const usersResource = useService(UsersResource); - const userInfoService = useService(UserInfoResource); const state = useTabState(() => ({ origin: null, properties: [], @@ -54,9 +53,6 @@ export const OriginInfoPanel: TabContainerPanelComponent = obser origin = user.origins[0]; } - const providerId = origin.subType ?? origin.type; - const authorized = userInfoService.hasToken(providerId); - const loadableState = useObjectRef(() => ({ get exception(): Error | null { return this.state.exception; @@ -109,7 +105,7 @@ export const OriginInfoPanel: TabContainerPanelComponent = obser const { selected } = useTab(tabId); - useAutoLoad(loadableState, selected && authorized); + useAutoLoad(loadableState, selected); if (!selected) { return null; @@ -135,16 +131,6 @@ export const OriginInfoPanel: TabContainerPanelComponent = obser ); } - if (!authorized) { - return styled(style)( - - - loadableState.reload?.()} /> - - - ); - } - if (!origin || (state.loaded && state.properties.length === 0)) { return styled(style)(