Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(config-api): SAML TR metadata validation, user mgt spec for error and security issue #7930

Merged
merged 36 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
47d9dcf
feat(config-api): saml plugin changes for new fields
pujavs Feb 20, 2024
389d5a6
feat(config-api): kc link plugin endpoint
pujavs Feb 20, 2024
cdb8e8c
feat(config-api): kc link plugin endpoint
pujavs Feb 20, 2024
647cfe2
feat(config-api): kc link plugin endpoint
pujavs Feb 20, 2024
7bbf44d
feat(config-api): saml plugin changes
pujavs Feb 20, 2024
e7c304a
feat(config-api): kc plugin changes
pujavs Feb 20, 2024
7c5aa62
feat(config-api): saml plugin changes for metadata elements
pujavs Feb 21, 2024
08c1a2c
feat(config-api): resolved merge conflict
pujavs Feb 21, 2024
bd6e171
feat(config-api): resolved merge conflict
pujavs Feb 21, 2024
2e15494
feat(config-api): resolved merge conflict
pujavs Feb 21, 2024
9bca835
feat(config-api): saml metedata elements save
pujavs Feb 22, 2024
f67bdb8
Merge branch 'main' of https://github.com/JanssenProject/jans into ja…
pujavs Feb 22, 2024
d34f14b
feat(config-api): attribute validation check
pujavs Feb 22, 2024
182dd83
Merge branch 'main' of https://github.com/JanssenProject/jans into ja…
pujavs Feb 23, 2024
c07b76b
feat(config-api): attribute validation in schema
pujavs Feb 23, 2024
c2a66ac
Merge branch 'main' of https://github.com/JanssenProject/jans into ja…
pujavs Feb 23, 2024
565dc61
Merge branch 'main' of https://github.com/JanssenProject/jans into ja…
pujavs Feb 26, 2024
c6d8f26
feat(config-api): custom attribute verification in schema
pujavs Feb 26, 2024
2bea03f
Merge branch 'main' of https://github.com/JanssenProject/jans into ja…
pujavs Feb 26, 2024
5458a0f
Merge branch 'main' of https://github.com/JanssenProject/jans into ja…
pujavs Feb 27, 2024
cec52f6
Merge branch 'main' of https://github.com/JanssenProject/jans into ja…
pujavs Feb 27, 2024
5fc187b
feat(config-api): attribute check in schema name and client password …
pujavs Feb 27, 2024
ab40cfa
feat(config-api): attribute check in schema name and client password …
pujavs Feb 27, 2024
a551ee5
Merge branch 'main' of https://github.com/JanssenProject/jans into ja…
pujavs Feb 28, 2024
44f92ae
feat(config-api): saml plugin changes for sp metadata handling
pujavs Feb 28, 2024
b9bca2e
feat(config-api): saml plugin changes for sp metadata handling
pujavs Feb 28, 2024
45f87ea
Merge branch 'main' of https://github.com/JanssenProject/jans into ja…
pujavs Feb 29, 2024
1fc3dc4
feat(config-api): SAML TR enhacement for metadata field and filename
pujavs Feb 29, 2024
73a400e
feat(config-api): SAML TR enhacement for metadata field and filename
pujavs Feb 29, 2024
b550305
Merge branch 'main' of https://github.com/JanssenProject/jans into ja…
pujavs Mar 1, 2024
1ba66c3
feat(config-api): security issue for apache-mime4j-core
pujavs Mar 1, 2024
cdbd503
Merge branch 'main' of https://github.com/JanssenProject/jans into ja…
pujavs Mar 1, 2024
6e8f4a2
feat(config-api): exception handling for user creation
pujavs Mar 1, 2024
8890bea
fix(config-api): SAML TR metadata validation, user mgt spec for error…
pujavs Mar 1, 2024
714bf5a
fix(config-api): SAML TR metadata validation, user mgt spec for error…
pujavs Mar 1, 2024
c942f99
Merge branch 'main' into jans-config-api-issues
yuriyz Mar 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions jans-config-api/docs/jans-config-api-swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7898,18 +7898,18 @@ components:
type: boolean
whitePagesCanView:
type: boolean
adminCanView:
type: boolean
adminCanEdit:
type: boolean
userCanEdit:
type: boolean
adminCanView:
type: boolean
userCanView:
type: boolean
userCanAccess:
type: boolean
adminCanAccess:
type: boolean
userCanAccess:
type: boolean
baseDn:
type: string
PatchRequest:
Expand Down Expand Up @@ -10180,10 +10180,10 @@ components:
ttl:
type: integer
format: int32
persisted:
type: boolean
opbrowserState:
type: string
persisted:
type: boolean
SessionIdAccessMap:
type: object
properties:
Expand Down
44 changes: 41 additions & 3 deletions jans-config-api/plugins/docs/kc-saml-plugin-swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -686,10 +686,26 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/TrustRelationship'
"400":
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
"401":
description: Unauthorized
"404":
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
"500":
description: InternalServerError
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
security:
- oauth2:
- https://jans.io/oauth/config/saml.write
Expand All @@ -716,10 +732,26 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/TrustRelationship'
"400":
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
"401":
description: Unauthorized
"404":
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
"500":
description: InternalServerError
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
security:
- oauth2:
- https://jans.io/oauth/config/saml.write
Expand Down Expand Up @@ -1070,10 +1102,7 @@ components:
type: string
enum:
- file
- uri
- federation
- manual
- mdq
samlMetadata:
$ref: '#/components/schemas/SAMLMetadata'
redirectUris:
Expand Down Expand Up @@ -1129,6 +1158,15 @@ components:
metaDataFile:
type: string
format: binary
ApiError:
type: object
properties:
code:
type: string
message:
type: string
description:
type: string
securitySchemes:
oauth2:
type: oauth2
Expand Down
35 changes: 35 additions & 0 deletions jans-config-api/plugins/docs/user-mgt-plugin-swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -324,12 +324,24 @@ paths:
}
"400":
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
"401":
description: Unauthorized
"404":
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
"500":
description: InternalServerError
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
security:
- oauth2:
- https://jans.io/oauth/config/user.write
Expand Down Expand Up @@ -528,10 +540,24 @@ paths:
}
"400":
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
"401":
description: Unauthorized
"404":
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
"500":
description: InternalServerError
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
security:
- oauth2:
- https://jans.io/oauth/config/user.write
Expand Down Expand Up @@ -882,6 +908,15 @@ components:
type: string
baseDn:
type: string
ApiError:
type: object
properties:
code:
type: string
message:
type: string
description:
type: string
UserPagedResult:
type: object
properties:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*/
public enum MetadataSourceType implements AttributeEnum {

FILE("file", "File",1), URI("uri", "URI",2), FEDERATION("federation", "Federation",3), MANUAL("manual", "Manual",4), MDQ("mdq", "MDQ",5);
FILE("file", "File",1), MANUAL("manual", "Manual",2);

private final String value;
private final String displayName;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package io.jans.configapi.plugin.saml.rest;

import static io.jans.as.model.util.Util.escapeLog;
import io.jans.configapi.plugin.saml.model.TrustRelationship;
import io.jans.configapi.plugin.saml.form.TrustRelationshipForm;
import io.jans.configapi.core.model.ApiError;
import io.jans.configapi.core.rest.BaseResource;
import io.jans.configapi.core.rest.ProtectedApi;
import io.jans.configapi.plugin.saml.model.MetadataSourceType;
import io.jans.configapi.plugin.saml.model.TrustRelationship;
import io.jans.configapi.plugin.saml.form.TrustRelationshipForm;
import io.jans.configapi.plugin.saml.util.Constants;
import io.jans.configapi.util.AttributeNames;
import io.jans.configapi.plugin.saml.service.SamlService;
Expand All @@ -31,6 +33,7 @@
import java.util.*;
import java.util.stream.*;

import org.apache.commons.lang.StringUtils;
import org.jboss.resteasy.annotations.providers.multipart.MultipartForm;
import org.slf4j.Logger;

Expand All @@ -44,6 +47,8 @@ public class TrustRelationshipResource extends BaseResource {
private static final String SAML_TRUST_RELATIONSHIP_CHECK_STR = "Trust Relationship identified by '";
private static final String NAME_CONFLICT = "NAME_CONFLICT";
private static final String NAME_CONFLICT_MSG = "Trust Relationship with same name `%s` already exists!";
private static final String DATA_NULL_CHK = "RESOURCE_IS_NULL";
private static final String DATA_NULL_MSG = "`%s` should not be null!";

@Inject
Logger logger;
Expand Down Expand Up @@ -95,8 +100,11 @@ public Response getTrustRelationshipById(
@RequestBody(description = "Trust Relationship object", content = @Content(mediaType = MediaType.MULTIPART_FORM_DATA, schema = @Schema(implementation = TrustRelationshipForm.class), examples = @ExampleObject(name = "Request example", value = "example/trust-relationship/trust-relationship-post.json")))
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "Newly created Trust Relationship", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = TrustRelationship.class))),
@ApiResponse(responseCode = "400", description = "Bad Request" , content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "BadRequestException"))),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "500", description = "InternalServerError") })
@ApiResponse(responseCode = "404", description = "Not Found" , content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "NotFoundException"))),
@ApiResponse(responseCode = "500", description = "InternalServerError", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "InternalServerError"))),
})
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Path("/upload")
@ProtectedApi(scopes = { Constants.SAML_WRITE_ACCESS }, groupScopes = {}, superScopes = {
Expand Down Expand Up @@ -127,6 +135,7 @@ public Response createTrustRelationshipWithFile(@MultipartForm TrustRelationship
logger.debug(" Create metaDataFile.available():{}", metaDataFile.available());
}

validateSpMetaDataSourceType(trustRelationship, metaDataFile);
String inum = samlService.generateInumForNewRelationship();
trustRelationship.setInum(inum);
trustRelationship.setDn(samlService.getDnForTrustRelationship(inum));
Expand All @@ -143,8 +152,11 @@ public Response createTrustRelationshipWithFile(@MultipartForm TrustRelationship
@RequestBody(description = "Trust Relationship object", content = @Content(mediaType = MediaType.MULTIPART_FORM_DATA, schema = @Schema(implementation = TrustRelationshipForm.class), examples = @ExampleObject(name = "Request example", value = "example/trust-relationship/trust-relationship-put.json")))
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = TrustRelationship.class))),
@ApiResponse(responseCode = "400", description = "Bad Request" , content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "BadRequestException"))),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "500", description = "InternalServerError") })
@ApiResponse(responseCode = "404", description = "Not Found" , content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "NotFoundException"))),
@ApiResponse(responseCode = "500", description = "InternalServerError", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "InternalServerError"))),
})
@ProtectedApi(scopes = { Constants.SAML_WRITE_ACCESS })
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Path("/upload")
Expand Down Expand Up @@ -193,8 +205,8 @@ public Response updateTrustRelationship(@MultipartForm TrustRelationshipForm tru
if (metaDataFile != null) {
logger.debug(" Create metaDataFile.available():{}", metaDataFile.available());
}


validateSpMetaDataSourceType(trustRelationship, metaDataFile);
// Update
trustRelationship = samlService.updateTrustRelationship(trustRelationship);

Expand Down Expand Up @@ -245,5 +257,45 @@ public Response processMetadataFiles() {

return Response.ok().build();
}

private void validateSpMetaDataSourceType(TrustRelationship trustRelationship, InputStream metaDataFile)
throws IOException {
logger.info("Validate SP MetaDataSourceType trustRelationship:{}, metaDataFile:{}", trustRelationship,
metaDataFile);

checkResourceNotNull(trustRelationship.getSpMetaDataSourceType(), "SP MetaData Source Type");

logger.info("Validate trustRelationship.getSpMetaDataSourceType():{}",
trustRelationship.getSpMetaDataSourceType());

if (trustRelationship.getSpMetaDataSourceType().equals(MetadataSourceType.FILE)) {

if (metaDataFile == null || metaDataFile.available() <= 0) {
throwBadRequestException(DATA_NULL_CHK, String.format(DATA_NULL_MSG, "SP MetaData File"));
}

// Since SP Metadata source is File set SamlMetadata manual elements to null
trustRelationship.setSamlMetadata(null);

} else if (trustRelationship.getSpMetaDataSourceType().equals(MetadataSourceType.MANUAL)) {

if (metaDataFile != null && metaDataFile.available() > 0) {
throwBadRequestException("SP MetaData File should not be provided!");
}

checkResourceNotNull(trustRelationship.getSamlMetadata(), "'SamlMetadata manual elements'");
checkNotNull(trustRelationship.getSamlMetadata().getEntityId(), "'EntityId'");
checkNotNull(trustRelationship.getSamlMetadata().getNameIDPolicyFormat(),
"'NameIDPolicyFormat'");
checkNotNull(trustRelationship.getSamlMetadata().getSingleLogoutServiceUrl(),
"'SingleLogoutServiceUrl'");
if (StringUtils.isBlank(trustRelationship.getSamlMetadata().getJansAssertionConsumerServiceGetURL())
&& (StringUtils
.isBlank(trustRelationship.getSamlMetadata().getJansAssertionConsumerServiceGetURL()))) {
throwBadRequestException("Either of AssertionConsumerService GET or POST URL should be provided!");
}
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.github.fge.jsonpatch.JsonPatchException;
import io.jans.as.common.model.common.User;
import io.jans.configapi.core.model.ApiError;
import io.jans.configapi.core.rest.BaseResource;
import io.jans.configapi.core.rest.ProtectedApi;
import io.jans.configapi.plugin.mgt.model.user.CustomUser;
Expand Down Expand Up @@ -134,9 +135,11 @@ public Response getUserByInum(
@RequestBody(description = "User object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomUser.class), examples = @ExampleObject(name = "Request json example", value = "example/user/user-post.json")))
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "Created", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomUser.class, description = "Created Object"), examples = @ExampleObject(name = "Response json example", value = "example/user/user.json"))),
@ApiResponse(responseCode = "400", description = "Bad Request"),
@ApiResponse(responseCode = "400", description = "Bad Request" , content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "BadRequestException"))),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "500", description = "InternalServerError") })
@ApiResponse(responseCode = "404", description = "Not Found" , content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "NotFoundException"))),
@ApiResponse(responseCode = "500", description = "InternalServerError", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "InternalServerError"))),
})
@POST
@ProtectedApi(scopes = { ApiAccessConstants.USER_WRITE_ACCESS })
public Response createUser(@Valid CustomUser customUser,
Expand All @@ -147,6 +150,7 @@ public Response createUser(@Valid CustomUser customUser,
removeNonLDAPAttributes);
}

try {
// get User object
User user = setUserAttributes(customUser);

Expand All @@ -168,6 +172,10 @@ public Response createUser(@Valid CustomUser customUser,
// get custom user
customUser = getCustomUser(user, removeNonLDAPAttributes);
logger.info("newly created customUser:{}", customUser);
}catch(WebApplicationException waex) {
logger.error("ApplicationException while creating user is:", waex);
throwInternalServerException("USER_CREATION", waex.getMessage());
}

return Response.status(Response.Status.CREATED).entity(customUser).build();
}
Expand All @@ -178,10 +186,11 @@ public Response createUser(@Valid CustomUser customUser,
@RequestBody(description = "User object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomUser.class), examples = @ExampleObject(name = "Request json example", value = "example/user/user.json")))
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomUser.class), examples = @ExampleObject(name = "Response json example", value = "example/user/user.json"))),
@ApiResponse(responseCode = "400", description = "Bad Request"),
@ApiResponse(responseCode = "400", description = "Bad Request" , content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "BadRequestException"))),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "Not Found"),
@ApiResponse(responseCode = "500", description = "InternalServerError") })
@ApiResponse(responseCode = "404", description = "Not Found" , content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "NotFoundException"))),
@ApiResponse(responseCode = "500", description = "InternalServerError", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "InternalServerError"))),
})
@PUT
@ProtectedApi(scopes = { ApiAccessConstants.USER_WRITE_ACCESS })
public Response updateUser(@Valid CustomUser customUser,
Expand Down
2 changes: 1 addition & 1 deletion jans-config-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
<swagger-maven-plugin-jakarta>2.2.19</swagger-maven-plugin-jakarta>
<swagger-models-jakarta>2.2.7</swagger-models-jakarta>

<apache.james.version>0.8.9</apache.james.version>
<apache.james.version>0.8.10</apache.james.version>
</properties>

<prerequisites>
Expand Down
Loading