From 6954a5cee3590aeb976130420c33b0f70a942e0f Mon Sep 17 00:00:00 2001 From: Maverick Studer Date: Thu, 15 Feb 2024 13:53:33 +0100 Subject: [PATCH] RED-8477: SSO settings endpoint for SAML --- ...IdentityProviderConfigurationResource.java | 8 +-- .../controller/ControllerAdvice.java | 28 ++++++++++ ...entityProviderConfigurationController.java | 6 +-- .../model/IdentityProviderConfigModel.java | 54 +++++++++---------- .../model/IdentityProviderConfigRequest.java | 27 +++++----- .../model/IdentityProviderModel.java | 16 +++--- .../model/IdentityProviderRequest.java | 8 +-- ...IdentityProviderWithDescriptorRequest.java | 12 ++--- 8 files changed, 93 insertions(+), 66 deletions(-) diff --git a/src/main/java/com/knecon/fforesight/tenantusermanagement/api/external/IdentityProviderConfigurationResource.java b/src/main/java/com/knecon/fforesight/tenantusermanagement/api/external/IdentityProviderConfigurationResource.java index 29e439c..fdbb59a 100644 --- a/src/main/java/com/knecon/fforesight/tenantusermanagement/api/external/IdentityProviderConfigurationResource.java +++ b/src/main/java/com/knecon/fforesight/tenantusermanagement/api/external/IdentityProviderConfigurationResource.java @@ -9,7 +9,6 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; @@ -20,6 +19,7 @@ import com.knecon.fforesight.tenantusermanagement.model.IdentityProviderWithDesc import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; +import org.springframework.web.bind.annotation.RequestBody; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; @@ -56,7 +56,7 @@ public interface IdentityProviderConfigurationResource { @PostMapping(value = API_PATH, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Creates a new identity provider", description = "None") @ApiResponses(value = {@ApiResponse(responseCode = "201", description = "Successfully created the identity provider"), @ApiResponse(responseCode = "400", description = "Malformed request parameters or body"), @ApiResponse(responseCode = "409", description = "Duplicate")}) - ResponseEntity createIdentityProvider(@RequestBody IdentityProviderRequest identityProvider); + ResponseEntity createIdentityProvider(@io.swagger.v3.oas.annotations.parameters.RequestBody @RequestBody IdentityProviderRequest identityProvider); @ResponseStatus(value = HttpStatus.CREATED) @@ -64,7 +64,7 @@ public interface IdentityProviderConfigurationResource { @PostMapping(value = API_PATH + IMPORT_SUB_PATH, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Creates a new identity provider", description = "None") @ApiResponses(value = {@ApiResponse(responseCode = "201", description = "Successfully created the identity provider"), @ApiResponse(responseCode = "400", description = "Malformed request parameters or body"), @ApiResponse(responseCode = "409", description = "Duplicate")}) - ResponseEntity createIdentityProviderFromDescriptor(@RequestBody IdentityProviderWithDescriptorRequest identityProvider); + ResponseEntity createIdentityProviderFromDescriptor(@io.swagger.v3.oas.annotations.parameters.RequestBody @RequestBody IdentityProviderWithDescriptorRequest identityProvider); @ResponseStatus(value = HttpStatus.OK) @@ -73,7 +73,7 @@ public interface IdentityProviderConfigurationResource { @Operation(summary = "Updates an existing identity provider", description = "None") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Successfully updated the identity provider"), @ApiResponse(responseCode = "404", description = "Not found"), @ApiResponse(responseCode = "400", description = "Malformed request parameters or body")}) ResponseEntity updateIdentityProvider(@Parameter(name = IDENTITY_PROVIDER_ALIAS_PARAM, description = "The alias of the identity provider to retrieve.", required = true) @PathVariable(IDENTITY_PROVIDER_ALIAS_PARAM) String identityProviderAlias, - @RequestBody IdentityProviderRequest identityProvider); + @io.swagger.v3.oas.annotations.parameters.RequestBody @RequestBody IdentityProviderRequest identityProvider); @ResponseStatus(value = HttpStatus.NO_CONTENT) diff --git a/src/main/java/com/knecon/fforesight/tenantusermanagement/controller/ControllerAdvice.java b/src/main/java/com/knecon/fforesight/tenantusermanagement/controller/ControllerAdvice.java index fdca2de..ad09260 100644 --- a/src/main/java/com/knecon/fforesight/tenantusermanagement/controller/ControllerAdvice.java +++ b/src/main/java/com/knecon/fforesight/tenantusermanagement/controller/ControllerAdvice.java @@ -2,12 +2,15 @@ package com.knecon.fforesight.tenantusermanagement.controller; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.security.access.AccessDeniedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.server.ResponseStatusException; +import com.fasterxml.jackson.databind.exc.InvalidFormatException; +import com.knecon.fforesight.tenantusermanagement.exception.ConflictException; import com.knecon.fforesight.tenantusermanagement.model.ErrorMessage; import jakarta.ws.rs.BadRequestException; @@ -37,6 +40,7 @@ public class ControllerAdvice { return new ResponseEntity<>(new ErrorMessage(e.getMessage()), HttpStatus.FORBIDDEN); } + @ExceptionHandler(ResponseStatusException.class) public ResponseEntity handleResponseStatusException(ResponseStatusException e) { @@ -50,6 +54,7 @@ public class ControllerAdvice { return new ResponseEntity<>(new ErrorMessage(e.getMessage()), HttpStatus.BAD_REQUEST); } + @ExceptionHandler(AccessDeniedException.class) public ResponseEntity handleAccessDeniedException(AccessDeniedException e) { @@ -57,4 +62,27 @@ public class ControllerAdvice { } + @ExceptionHandler(ConflictException.class) + public ResponseEntity handleConflictException(ConflictException e) { + + return new ResponseEntity<>(new ErrorMessage(e.getMessage()), HttpStatus.CONFLICT); + } + + @ExceptionHandler({HttpMessageNotReadableException.class}) + public ResponseEntity handleHttpMessageNotReadableException(HttpMessageNotReadableException e) { + + String errorMessage = e.getMessage(); + var cause = e.getCause(); + if (cause instanceof InvalidFormatException invalidFormatException) { + + errorMessage = cause.getMessage(); + Class targetType = invalidFormatException.getTargetType(); + if (targetType != null && targetType.isEnum()) { + errorMessage = String.format("Unsupported value for %s", targetType.getSimpleName()); + } + } + + return new ResponseEntity<>(new ErrorMessage(errorMessage), HttpStatus.BAD_REQUEST); + } + } diff --git a/src/main/java/com/knecon/fforesight/tenantusermanagement/controller/external/IdentityProviderConfigurationController.java b/src/main/java/com/knecon/fforesight/tenantusermanagement/controller/external/IdentityProviderConfigurationController.java index eabde35..63d3db0 100644 --- a/src/main/java/com/knecon/fforesight/tenantusermanagement/controller/external/IdentityProviderConfigurationController.java +++ b/src/main/java/com/knecon/fforesight/tenantusermanagement/controller/external/IdentityProviderConfigurationController.java @@ -119,12 +119,12 @@ public class IdentityProviderConfigurationController implements IdentityProvider IdentityProviderModel createdIdentityProvider = getIdentityProvider(identityProviderModel.getAlias()); return new ResponseEntity<>(createdIdentityProvider, HttpStatus.valueOf(response.getStatus())); } - case CONFLICT -> throw new IdentityProviderExistsAlreadyException(response.getStatusInfo().getReasonPhrase()); + case CONFLICT -> throw new IdentityProviderExistsAlreadyException(identityProviderModel.getAlias()); default -> { if (httpStatus.is4xxClientError()) { throw new ResponseStatusException(httpStatus, "Bad request to keycloak API"); } else { - throw new ResponseStatusException(httpStatus); + throw new ResponseStatusException(httpStatus, httpStatus.getReasonPhrase()); } } } @@ -156,7 +156,7 @@ public class IdentityProviderConfigurationController implements IdentityProvider } else if (httpStatus.is4xxClientError()) { throw new ResponseStatusException(httpStatus, "Bad request to keycloak API"); } else { - throw new ResponseStatusException(httpStatus); + throw new ResponseStatusException(httpStatus, httpStatus.getReasonPhrase()); } } catch (HttpClientErrorException e) { throw new ResponseStatusException(e.getStatusCode(), extractKeycloakErrorMessageInfos(e.getMessage())); diff --git a/src/main/java/com/knecon/fforesight/tenantusermanagement/model/IdentityProviderConfigModel.java b/src/main/java/com/knecon/fforesight/tenantusermanagement/model/IdentityProviderConfigModel.java index 5a54b49..c7fbe1f 100644 --- a/src/main/java/com/knecon/fforesight/tenantusermanagement/model/IdentityProviderConfigModel.java +++ b/src/main/java/com/knecon/fforesight/tenantusermanagement/model/IdentityProviderConfigModel.java @@ -19,104 +19,104 @@ import lombok.NoArgsConstructor; public class IdentityProviderConfigModel implements ExtensibleModel { @Builder.Default - @Schema(description = "Flag indicating whether creation is allowed (default: true)") + @Schema(description = "Whether the external identity provider is allowed to create a new identifier to represent the principal") private Boolean allowCreate = true; @Builder.Default - @Schema(description = "Order for GUI display (default: 0)") + @Schema(description = "Display order : It defines the order of the providers in GUI (for example, on the Login page). The lowest number will be applied first.") private Integer guiOrder = 0; - @Schema(description = "Entity ID") + @Schema(description = "Service provider entity ID : It is used to uniquely identify this SAML Service Provider.") private String entityId; - @Schema(description = "Identity Provider Entity ID") + @Schema(description = "Identity provider entity ID : It is used to validate the Issuer for received SAML assertions. If empty, no Issuer validation is performed.") private String idpEntityId; - @Schema(description = "Single Sign-On Service URL") + @Schema(description = "The Url that must be used to send authentication requests (SAML AuthnRequest).") private String singleSignOnServiceUrl; @Builder.Default - @Schema(description = "Single Logout Service URL (default: empty string)") + @Schema(description = "The Url that must be used to send logout requests.") private String singleLogoutServiceUrl = ""; @Builder.Default - @Schema(description = "Attribute Consuming Service Name (default: empty string)") + @Schema(description = "Name of the Attribute Consuming Service profile to advertise in the SP metadata.") private String attributeConsumingServiceName = ""; @Builder.Default - @Schema(description = "Flag indicating backchannel support (default: false)") + @Schema(description = "Backchannel logout : Does the external IDP support backchannel logout?") private Boolean backchannelSupported = false; @Builder.Default - @Schema(description = "NameID Policy Format (default: PERSISTENT)") + @Schema(description = "Specifies the URI reference corresponding to a name identifier format.") private IdentityProviderNameIDPolicyFormat nameIDPolicyFormat = IdentityProviderNameIDPolicyFormat.PERSISTENT; @Builder.Default - @Schema(description = "Principal Type (default: SUBJECT_NAME_ID)") + @Schema(description = "Used to identify and track external users from the assertion. Default is using Subject NameID, alternatively can be set up as identifying attribute.") private IdentityProviderPrincipalType principalType = IdentityProviderPrincipalType.SUBJECT; @Builder.Default - @Schema(description = "Flag indicating post-binding response support (default: false)") + @Schema(description = "HTTP-POST binding response : Indicates whether to respond to requests using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used.") private Boolean postBindingResponse = false; @Builder.Default - @Schema(description = "Flag indicating post-binding authentication request support (default: false)") + @Schema(description = "HTTP-POST binding for AuthnRequest : Indicates whether the AuthnRequest must be sent using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used.") private Boolean postBindingAuthnRequest = false; @Builder.Default - @Schema(description = "Flag indicating post-binding logout support (default: false)") + @Schema(description = "HTTP-POST binding logout : Indicates whether to respond to requests using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used.") private Boolean postBindingLogout = false; @Builder.Default - @Schema(description = "Flag indicating whether Authn requests should be signed (default: false)") + @Schema(description = "Indicates whether the identity provider expects a signed AuthnRequest.") private Boolean wantAuthnRequestsSigned = false; @Builder.Default - @Schema(description = "Flag indicating whether assertions should be signed (default: false)") + @Schema(description = "Indicates whether this service provider expects a signed Assertion.") private Boolean wantAssertionsSigned = false; @Builder.Default - @Schema(description = "Flag indicating whether assertions should be encrypted (default: false)") + @Schema(description = "Indicates whether this service provider expects an encrypted Assertion.") private Boolean wantAssertionsEncrypted = false; @Builder.Default - @Schema(description = "Flag indicating whether force authentication is required (default: false)") + @Schema(description = "Force authentication : Indicates whether the identity provider must authenticate the presenter directly rather than rely on a previous security context.") private Boolean forceAuthn = false; @Builder.Default - @Schema(description = "Flag indicating whether signature validation is required (default: false)") + @Schema(description = "Enable/disable signature validation of external IDP signatures.") private Boolean validateSignature = false; @Builder.Default - @Schema(description = "Flag indicating whether to sign SP metadata (default: false)") + @Schema(description = "Sign service provider metadata : Enable/disable signature of the provider SAML metadata.") private Boolean signSpMetadata = false; @Builder.Default - @Schema(description = "Flag indicating whether login hInteger is supported (default: false)") - private Boolean loginHInteger = false; + @Schema(description = "Pass subject : During login phase, forward an optional login_hint query parameter to SAML AuthnRequest's Subject.") + private Boolean loginHint = false; @Builder.Default - @Schema(description = "Allowed clock skew in seconds (default: 0)") + @Schema(description = "Clock skew in seconds that is tolerated when validating identity provider tokens. Default value is zero.") private Integer allowedClockSkew = 0; @Builder.Default - @Schema(description = "Attribute Consuming Service Index (default: 0)") + @Schema(description = "Index of the Attribute Consuming Service profile to request during authentication.") private Integer attributeConsumingServiceIndex = 0; @Builder.Default - @Schema(description = "Flag indicating whether login is only possible if requested explicitly (default: false)") + @Schema(description = "If hidden, login with this provider is possible only if requested explicitly, for example using the 'kc_idp_hint' parameter.") private Boolean hideOnLoginPage = false; @Builder.Default - @Schema(description = "Sync mode of the mapper (default: IMPORT)") + @Schema(description = "Default sync mode for all mappers. The sync mode determines when user data will be synced using the mappers. Possible values are: 'legacy' to keep the behaviour before this option was introduced, 'import' to only import the user once during first login of the user with this identity provider, 'force' to always update the user during every login with this identity provider.") @JsonInclude(JsonInclude.Include.NON_NULL) private IdentityProviderSyncMode syncMode = IdentityProviderSyncMode.IMPORT; + @Schema(description = "The signature algorithm to use to sign documents. Note that 'SHA1' based algorithms are deprecated and can be removed in the future. It is recommended to stick to some more secure algorithm instead of '*_SHA1'.") @JsonInclude(JsonInclude.Include.NON_NULL) - @Schema(description = "Sync mode of the mapper (only used when wantAuthnRequestsSigned is true)") private IdentityProviderSignatureAlgorithm signatureAlgorithm; - @Schema(description = "SAML signature key name (only used when wantAuthnRequestsSigned is true)") + @Schema(description = "SAML signature key name : Signed SAML documents contain identification of signing key in KeyName element. For Keycloak / RH-SSO counter-party, use KEY_ID, for MS AD FS use CERT_SUBJECT, for others check and use NONE if no other option works.") @JsonInclude(JsonInclude.Include.NON_NULL) private IdentityProviderSAMLSignatureKeyName xmlSigKeyInfoKeyNameTransformer; diff --git a/src/main/java/com/knecon/fforesight/tenantusermanagement/model/IdentityProviderConfigRequest.java b/src/main/java/com/knecon/fforesight/tenantusermanagement/model/IdentityProviderConfigRequest.java index 017d302..9a1b211 100644 --- a/src/main/java/com/knecon/fforesight/tenantusermanagement/model/IdentityProviderConfigRequest.java +++ b/src/main/java/com/knecon/fforesight/tenantusermanagement/model/IdentityProviderConfigRequest.java @@ -10,53 +10,52 @@ import lombok.NoArgsConstructor; @Builder @AllArgsConstructor @NoArgsConstructor -@Schema(description = "Object containing information about an identity provider configuration.") +@Schema(description = "Create request for the identity provider configuration.") public class IdentityProviderConfigRequest { @Builder.Default - @Schema(description = "Flag indicating whether creation is allowed (default: true)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @Schema(description = "Whether the external identity provider is allowed to create a new identifier to represent the principal (default: true)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private Boolean allowCreate = true; @Builder.Default - @Schema(description = "Order for GUI display (default: 0)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @Schema(description = "Display order : It defines the order of the providers in GUI (for example, on the Login page). The lowest number will be applied first. (default: 0)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private Integer guiOrder = 0; - @Schema(description = "Entity ID") + @Schema(description = "Service provider entity ID : It is used to uniquely identify this SAML Service Provider.", requiredMode = Schema.RequiredMode.REQUIRED) private String entityId; - @Schema(description = "Identity Provider Entity ID") + @Schema(description = "Identity provider entity ID : It is used to validate the Issuer for received SAML assertions. If empty, no Issuer validation is performed.", requiredMode = Schema.RequiredMode.REQUIRED) private String idpEntityId; - @Schema(description = "Single Sign-On Service URL") + @Schema(description = "The Url that must be used to send authentication requests (SAML AuthnRequest).", requiredMode = Schema.RequiredMode.REQUIRED) private String singleSignOnServiceUrl; @Builder.Default - @Schema(description = "NameID Policy Format (default: PERSISTENT)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @Schema(description = "Specifies the URI reference corresponding to a name identifier format. (default: PERSISTENT)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private IdentityProviderNameIDPolicyFormat nameIDPolicyFormat = IdentityProviderNameIDPolicyFormat.PERSISTENT; @Builder.Default - @Schema(description = "Principal Type (default: SUBJECT)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @Schema(description = "Used to identify and track external users from the assertion. Default is using Subject NameID, alternatively can be set up as identifying attribute. (default: SUBJECT)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private IdentityProviderPrincipalType principalType = IdentityProviderPrincipalType.SUBJECT; @Builder.Default - @Schema(description = "Flag indicating post-binding response support (default: false)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @Schema(description = "HTTP-POST binding response : Indicates whether to respond to requests using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used. (default: false)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private Boolean postBindingResponse = false; @Builder.Default - @Schema(description = "Flag indicating post-binding authentication request support (default: false)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @Schema(description = "HTTP-POST binding for AuthnRequest : Indicates whether the AuthnRequest must be sent using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used. (default: false)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private Boolean postBindingAuthnRequest = false; @Builder.Default - @Schema(description = "Flag indicating whether Authn requests should be signed (default: false)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @Schema(description = "Indicates whether the identity provider expects a signed AuthnRequest. (default: false)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private Boolean wantAuthnRequestsSigned = false; @Builder.Default - @Schema(description = "Sync mode of the mapper (only used when wantAuthnRequestsSigned is true)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @Schema(description = "The signature algorithm to use to sign documents. Note that 'SHA1' based algorithms are deprecated and can be removed in the future. It is recommended to stick to some more secure algorithm instead of '*_SHA1'. (only used when wantAuthnRequestsSigned is true, default: RSA_SHA256)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private IdentityProviderSignatureAlgorithm signatureAlgorithm = IdentityProviderSignatureAlgorithm.RSA_SHA256; @Builder.Default - @Schema(description = "SAML signature key name (only used when wantAuthnRequestsSigned is true)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @Schema(description = "SAML signature key name : Signed SAML documents contain identification of signing key in KeyName element. For Keycloak / RH-SSO counter-party, use KEY_ID, for MS AD FS use CERT_SUBJECT, for others check and use NONE if no other option works. (only used when wantAuthnRequestsSigned is true, default: KEY_ID)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private IdentityProviderSAMLSignatureKeyName xmlSigKeyInfoKeyNameTransformer = IdentityProviderSAMLSignatureKeyName.KEY_ID; - } diff --git a/src/main/java/com/knecon/fforesight/tenantusermanagement/model/IdentityProviderModel.java b/src/main/java/com/knecon/fforesight/tenantusermanagement/model/IdentityProviderModel.java index bd35dd6..f3141bf 100644 --- a/src/main/java/com/knecon/fforesight/tenantusermanagement/model/IdentityProviderModel.java +++ b/src/main/java/com/knecon/fforesight/tenantusermanagement/model/IdentityProviderModel.java @@ -18,7 +18,7 @@ import lombok.NoArgsConstructor; @Schema(description = "Object containing information about an identity provider.") public class IdentityProviderModel implements ExtensibleModel { - @Schema(description = "Alias of the identity provider") + @Schema(description = "Alias of the identity provider used for identification") private String alias; @Builder.Default @@ -26,31 +26,31 @@ public class IdentityProviderModel implements ExtensibleModel { private IdentityProviderConfigModel config = new IdentityProviderConfigModel(); @Builder.Default - @Schema(description = "Display name of the identity provider (optional)") + @Schema(description = "Display name of the identity provider in keycloak") private String displayName = ""; @Builder.Default - @Schema(description = "Provider ID of the identity provider") + @Schema(description = "The ID of the SSO technology provider") private String providerId = "saml"; @Builder.Default - @Schema(description = "Whether tokens are to be stored (optional)") + @Schema(description = "Enable/disable if tokens must be stored after authenticating users.") private Boolean storeToken = false; @Builder.Default - @Schema(description = "Whether new users can read any stored tokens (optional)") + @Schema(description = "Stored tokens readable : Enable/disable if new users can read any stored tokens. This assigns the broker.read-token role.") private Boolean addReadTokenRoleOnCreate = false; @Builder.Default - @Schema(description = "Whether emails are to be trusted (optional)") + @Schema(description = "If enabled, email provided by this provider is not verified even if verification is enabled for the realm.") private Boolean trustEmail = false; @Builder.Default - @Schema(description = "Whether users can only link and not log in through this provider (optional)") + @Schema(description = "Account linking only : If true, users cannot log in through this provider. They can only link to this provider. This is useful if you don't want to allow login from the provider, but want to integrate with a provider") private Boolean linkOnly = false; @Builder.Default - @Schema(description = "Alias of the authentication flow, which is triggered after first login with this identity provider (optional)") + @Schema(description = "First login flow : Alias of authentication flow, which is triggered after first login with this identity provider. Term 'First Login' means that no Keycloak account is currently linked to the authenticated identity provider account.") private String firstBrokerLoginFlowAlias = "first broker login"; @Builder.Default diff --git a/src/main/java/com/knecon/fforesight/tenantusermanagement/model/IdentityProviderRequest.java b/src/main/java/com/knecon/fforesight/tenantusermanagement/model/IdentityProviderRequest.java index 10dbafe..9213109 100644 --- a/src/main/java/com/knecon/fforesight/tenantusermanagement/model/IdentityProviderRequest.java +++ b/src/main/java/com/knecon/fforesight/tenantusermanagement/model/IdentityProviderRequest.java @@ -13,19 +13,19 @@ import lombok.NoArgsConstructor; @Schema(description = "Create or update request for an identity provider.") public class IdentityProviderRequest { - @Schema(description = "Alias of the identity provider") + @Schema(description = "Alias of the identity provider used for identification", requiredMode = Schema.RequiredMode.REQUIRED) private String alias; @Builder.Default - @Schema(description = "Configuration of the identity provider") + @Schema(description = "Configuration of the identity provider", requiredMode = Schema.RequiredMode.REQUIRED) private IdentityProviderConfigRequest config = new IdentityProviderConfigRequest(); @Builder.Default - @Schema(description = "Display name of the identity provider (optional)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @Schema(description = "Display name of the identity provider in keycloak (optional, fallbacks to alias if empty)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private String displayName = ""; @Builder.Default - @Schema(description = "Provider ID of the identity provider", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @Schema(description = "The ID of the SSO technology provider (default: saml)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private String providerId = "saml"; } diff --git a/src/main/java/com/knecon/fforesight/tenantusermanagement/model/IdentityProviderWithDescriptorRequest.java b/src/main/java/com/knecon/fforesight/tenantusermanagement/model/IdentityProviderWithDescriptorRequest.java index b8fe13d..54ab54b 100644 --- a/src/main/java/com/knecon/fforesight/tenantusermanagement/model/IdentityProviderWithDescriptorRequest.java +++ b/src/main/java/com/knecon/fforesight/tenantusermanagement/model/IdentityProviderWithDescriptorRequest.java @@ -10,24 +10,24 @@ import lombok.NoArgsConstructor; @Builder @AllArgsConstructor @NoArgsConstructor -@Schema(description = "Create or update request for an identity provider.") +@Schema(description = "Create request for an identity provider using a SAML entity descriptor for a faster creation process.") public class IdentityProviderWithDescriptorRequest { - @Schema(description = "Alias of the identity provider", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "Alias of the identity provider used for identification", requiredMode = Schema.RequiredMode.REQUIRED) private String alias; @Builder.Default - @Schema(description = "Display name of the identity provider (optional)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @Schema(description = "Display name of the identity provider in keycloak (optional, fallbacks to alias if empty)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private String displayName = ""; @Builder.Default - @Schema(description = "Provider ID of the identity provider", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @Schema(description = "The ID of the SSO technology provider (default: saml)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private String providerId = "saml"; - @Schema(description = "External IDP metadata from a URL", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "The SAML entity descriptor as a URL to external IDP metadata, used to fill other fields for a faster identity provider creation process", requiredMode = Schema.RequiredMode.REQUIRED) private String samlEntityDescriptorURL; - @Schema(description = "Display name of the identity provider (optional)", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "Service provider entity ID that will be used to uniquely identify this SAML Service Provider", requiredMode = Schema.RequiredMode.REQUIRED) private String entityId; }