mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-10-12 09:18:20 +00:00
UI : Mask the JWT token in Metadata service (#8842)
* Mask the Jwt token in Metadata service * minor fix * fix the icon alignment in Add Ingestion button * disable the test connection for metadata service OpenMetadata type * change the css name * fix unit test issue * Fix Auth Provider * Fix add ingestion dropdown icon alignment * Fix formatting * Do not encryt JWT auth mechanism with secrets manager Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com> Co-authored-by: ulixius9 <mayursingal9@gmail.com> Co-authored-by: Sachin Chaurasiya <sachinchaurasiyachotey87@gmail.com> Co-authored-by: mohitdeuex <mohit.y@deuexsolutions.com> Co-authored-by: Nahuel Verdugo Revigliono <nahuel@getcollate.io>
This commit is contained in:
parent
b2c1e42f9b
commit
36f27e947d
@ -440,11 +440,15 @@ class OpenMetadataAuthenticationProvider(AuthenticationProvider):
|
||||
|
||||
def auth_token(self) -> None:
|
||||
if not self.jwt_token:
|
||||
if os.path.isfile(self.security_config.jwtToken):
|
||||
with open(self.security_config.jwtToken, "r", encoding="utf-8") as file:
|
||||
if os.path.isfile(self.security_config.jwtToken.get_secret_value()):
|
||||
with open(
|
||||
self.security_config.jwtToken.get_secret_value(),
|
||||
"r",
|
||||
encoding="utf-8",
|
||||
) as file:
|
||||
self.jwt_token = file.read().rstrip()
|
||||
else:
|
||||
self.jwt_token = self.security_config.jwtToken
|
||||
self.jwt_token = self.security_config.jwtToken.get_secret_value()
|
||||
|
||||
def get_access_token(self):
|
||||
self.auth_token()
|
||||
|
@ -20,11 +20,13 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import lombok.Getter;
|
||||
import org.openmetadata.annotations.PasswordField;
|
||||
import org.openmetadata.schema.entity.services.ServiceType;
|
||||
import org.openmetadata.schema.entity.services.ingestionPipelines.IngestionPipeline;
|
||||
import org.openmetadata.schema.entity.teams.AuthenticationMechanism;
|
||||
import org.openmetadata.schema.security.client.OpenMetadataJWTClientConfig;
|
||||
import org.openmetadata.schema.security.secrets.SecretsManagerProvider;
|
||||
import org.openmetadata.service.exception.InvalidServiceConnectionException;
|
||||
import org.openmetadata.service.exception.SecretsManagerException;
|
||||
@ -41,6 +43,8 @@ public abstract class SecretsManager {
|
||||
|
||||
private Fernet fernet;
|
||||
|
||||
private static final Set<Class<?>> DO_NOT_ENCRYPT_CLASSES = Set.of(OpenMetadataJWTClientConfig.class);
|
||||
|
||||
protected SecretsManager(SecretsManagerProvider secretsManagerProvider, String clusterPrefix) {
|
||||
this.secretsManagerProvider = secretsManagerProvider;
|
||||
this.clusterPrefix = clusterPrefix;
|
||||
@ -97,6 +101,7 @@ public abstract class SecretsManager {
|
||||
}
|
||||
|
||||
private void encryptPasswordFields(Object toEncryptObject, String secretId) {
|
||||
if (!DO_NOT_ENCRYPT_CLASSES.contains(toEncryptObject.getClass())) {
|
||||
// for each get method
|
||||
Arrays.stream(toEncryptObject.getClass().getMethods())
|
||||
.filter(this::isGetMethodOfObject)
|
||||
@ -122,6 +127,7 @@ public abstract class SecretsManager {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void decryptPasswordFields(Object toDecryptObject) {
|
||||
// for each get method
|
||||
|
@ -8,7 +8,8 @@
|
||||
"properties": {
|
||||
"jwtToken": {
|
||||
"description": "OpenMetadata generated JWT token.",
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"format": "password"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
|
@ -221,7 +221,7 @@ const Ingestion: React.FC<IngestionProps> = ({
|
||||
const getAddIngestionButton = (type: PipelineType) => {
|
||||
return (
|
||||
<Button
|
||||
className={classNames('tw-h-8 tw-rounded tw-mb-2')}
|
||||
className={classNames('h-8 rounded-4 m-b-xs')}
|
||||
data-testid="add-new-ingestion-button"
|
||||
size="small"
|
||||
type="primary"
|
||||
@ -235,7 +235,7 @@ const Ingestion: React.FC<IngestionProps> = ({
|
||||
return (
|
||||
<Fragment>
|
||||
<Button
|
||||
className={classNames('tw-h-8 tw-rounded tw-mb-2')}
|
||||
className={classNames('h-8 rounded-4 m-b-xs flex items-center')}
|
||||
data-testid="add-new-ingestion-button"
|
||||
size="small"
|
||||
type="primary"
|
||||
@ -245,15 +245,15 @@ const Ingestion: React.FC<IngestionProps> = ({
|
||||
<DropdownIcon
|
||||
style={{
|
||||
transform: 'rotate(180deg)',
|
||||
marginTop: '2px',
|
||||
verticalAlign: 'middle',
|
||||
color: '#fff',
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<DropdownIcon
|
||||
style={{
|
||||
marginTop: '2px',
|
||||
color: '#fff',
|
||||
verticalAlign: 'middle',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
@ -55,6 +55,7 @@ interface Props {
|
||||
status: LoadingState;
|
||||
onCancel?: () => void;
|
||||
onSave: (data: ISubmitEvent<ConfigData>) => void;
|
||||
disableTestConnection?: boolean;
|
||||
}
|
||||
|
||||
const ConnectionConfigForm: FunctionComponent<Props> = ({
|
||||
@ -66,6 +67,7 @@ const ConnectionConfigForm: FunctionComponent<Props> = ({
|
||||
status,
|
||||
onCancel,
|
||||
onSave,
|
||||
disableTestConnection = false,
|
||||
}: Props) => {
|
||||
const [isAirflowAvailable, setIsAirflowAvailable] = useState<boolean>(false);
|
||||
|
||||
@ -154,6 +156,7 @@ const ConnectionConfigForm: FunctionComponent<Props> = ({
|
||||
return (
|
||||
<FormBuilder
|
||||
cancelText={cancelText}
|
||||
disableTestConnection={disableTestConnection}
|
||||
formData={validConfig}
|
||||
isAirflowAvailable={isAirflowAvailable}
|
||||
okText={okText}
|
||||
|
@ -33,6 +33,7 @@ interface ServiceConfigProps {
|
||||
data: ConfigData,
|
||||
serviceCategory: ServiceCategory
|
||||
) => Promise<void>;
|
||||
disableTestConnection: boolean;
|
||||
}
|
||||
|
||||
export const Field = ({ children }: { children: React.ReactNode }) => {
|
||||
@ -45,6 +46,7 @@ const ServiceConfig = ({
|
||||
serviceType,
|
||||
data,
|
||||
handleUpdate,
|
||||
disableTestConnection,
|
||||
}: ServiceConfigProps) => {
|
||||
const history = useHistory();
|
||||
const [status, setStatus] = useState<LoadingState>('initial');
|
||||
@ -80,6 +82,7 @@ const ServiceConfig = ({
|
||||
| DashboardService
|
||||
| PipelineService
|
||||
}
|
||||
disableTestConnection={disableTestConnection}
|
||||
serviceCategory={serviceCategory}
|
||||
serviceType={serviceType}
|
||||
status={status}
|
||||
|
@ -17,7 +17,7 @@ import { faInfoCircle } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { isEmpty, isNull, isObject } from 'lodash';
|
||||
import React, { ReactNode, useEffect, useState } from 'react';
|
||||
import { DEF_UI_SCHEMA } from '../../constants/services.const';
|
||||
import { DEF_UI_SCHEMA, JWT_CONFIG } from '../../constants/services.const';
|
||||
import { EntityType } from '../../enums/entity.enum';
|
||||
import { DashboardServiceType } from '../../generated/entity/services/dashboardService';
|
||||
import { DatabaseServiceType } from '../../generated/entity/services/databaseService';
|
||||
@ -135,6 +135,15 @@ const ServiceConnectionDetails = ({
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
serviceCategory.slice(0, -1) === EntityType.METADATA_SERVICE &&
|
||||
key === 'securityConfig'
|
||||
) {
|
||||
const newSchemaPropertyObject = schemaPropertyObject[
|
||||
key
|
||||
].oneOf.filter((item) => item.title === JWT_CONFIG)[0].properties;
|
||||
|
||||
return getKeyValues(value, newSchemaPropertyObject);
|
||||
} else {
|
||||
return getKeyValues(
|
||||
value,
|
||||
|
@ -37,6 +37,7 @@ interface Props extends FormProps<ConfigData> {
|
||||
status?: LoadingState;
|
||||
onCancel?: () => void;
|
||||
onTestConnection?: (formData: ConfigData) => Promise<void>;
|
||||
disableTestConnection: boolean;
|
||||
}
|
||||
|
||||
const FormBuilder: FunctionComponent<Props> = ({
|
||||
@ -51,6 +52,7 @@ const FormBuilder: FunctionComponent<Props> = ({
|
||||
onTestConnection,
|
||||
uiSchema,
|
||||
isAirflowAvailable,
|
||||
disableTestConnection,
|
||||
...props
|
||||
}: Props) => {
|
||||
const formRef = useRef<CoreForm<ConfigData>>();
|
||||
@ -188,7 +190,7 @@ const FormBuilder: FunctionComponent<Props> = ({
|
||||
'tw-opacity-40': connectionTesting,
|
||||
})}
|
||||
data-testid="test-connection-btn"
|
||||
disabled={connectionTesting}
|
||||
disabled={connectionTesting || disableTestConnection}
|
||||
size="small"
|
||||
theme="primary"
|
||||
variant="outlined"
|
||||
|
@ -221,4 +221,5 @@ export const COMMON_UI_SCHEMA = {
|
||||
},
|
||||
};
|
||||
|
||||
export const OPENMETADATA = 'Openmetadata';
|
||||
export const OPENMETADATA = 'OpenMetadata';
|
||||
export const JWT_CONFIG = 'openMetadataJWTClientConfig';
|
||||
|
@ -26,6 +26,7 @@ import Loader from '../../components/Loader/Loader';
|
||||
import ServiceConfig from '../../components/ServiceConfig/ServiceConfig';
|
||||
import { GlobalSettingsMenuCategory } from '../../constants/globalSettings.constants';
|
||||
import { addServiceGuide } from '../../constants/service-guide.constant';
|
||||
import { OPENMETADATA } from '../../constants/services.const';
|
||||
import { PageLayoutType } from '../../enums/layout.enum';
|
||||
import { ServiceCategory } from '../../enums/service.enum';
|
||||
import { ConfigData, ServicesType } from '../../interface/service.interface';
|
||||
@ -159,6 +160,10 @@ function EditConnectionFormPage() {
|
||||
</h6>
|
||||
<ServiceConfig
|
||||
data={serviceDetails as ServicesData}
|
||||
disableTestConnection={
|
||||
ServiceCategory.METADATA_SERVICES === serviceCategory &&
|
||||
OPENMETADATA === serviceFQN
|
||||
}
|
||||
handleUpdate={handleConfigUpdate}
|
||||
serviceCategory={serviceCategory as ServiceCategory}
|
||||
serviceFQN={serviceFQN}
|
||||
|
@ -79,6 +79,16 @@
|
||||
.text-underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
// Radius
|
||||
|
||||
.rounded-4 {
|
||||
border-radius: 4px;
|
||||
}
|
||||
.rounded-full {
|
||||
border-radius: 9999px;
|
||||
}
|
||||
|
||||
// Width
|
||||
.w-4 {
|
||||
width: 16px;
|
||||
@ -249,10 +259,6 @@
|
||||
border-color: @gray;
|
||||
}
|
||||
|
||||
.rounded-full {
|
||||
border-radius: 9999px;
|
||||
}
|
||||
|
||||
.bg-primary-lite {
|
||||
background: @primary-light;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user