chore: restore from backup
restore the project to new gitea instance
This commit is contained in:
commit
b477a5f984
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/target/
|
||||||
|
/build/
|
||||||
|
/.classpath
|
||||||
|
/.project
|
||||||
|
/.factorypath
|
||||||
|
/password-authority.iml
|
||||||
|
/.idea/
|
||||||
|
/.settings/
|
||||||
|
|
||||||
|
/validation-authority.iml
|
||||||
96
README.md
Normal file
96
README.md
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
:small_orange_diamond: WORK IN PROGRESS :small_orange_diamond:
|
||||||
|
|
||||||
|
# Validation Authority
|
||||||
|
|
||||||
|
| characteristic | value | description |
|
||||||
|
| ------ | ------ | ------ |
|
||||||
|
| specification | JSON:API | https://jsonapi.org/format/ |
|
||||||
|
| base url (prod) | https://validationauthority.jkgroller ||
|
||||||
|
| base path | `/v1` | |
|
||||||
|
| content type | `application/vnd.api+json` | optional on `GET` |
|
||||||
|
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
### credentials
|
||||||
|
|
||||||
|
Characteristics:
|
||||||
|
|
||||||
|
| characteristic | description |
|
||||||
|
| ------ | ------ |
|
||||||
|
| type | `credentials` |
|
||||||
|
| resource path | `/credentials` |
|
||||||
|
| id | base62 url-safe uuid |
|
||||||
|
| supported methods | `POST` |
|
||||||
|
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
|
||||||
|
| name | type | allowed methods |
|
||||||
|
| ------ | ------ | ------ |
|
||||||
|
| username | char[] | `POST` |
|
||||||
|
| password | char[] | `POST` |
|
||||||
|
| valid | boolean | `GET` |
|
||||||
|
|
||||||
|
Status Codes:
|
||||||
|
|
||||||
|
| status | description |
|
||||||
|
| ------ | ------ |
|
||||||
|
| `201 CREATED` | For all successful `POST` requests. |
|
||||||
|
| `400 BAD REQUEST` | For all validation failure responses. Collection of `Error` objects returned. See below. |
|
||||||
|
| `405 METHOD NOT ALLOWED` | For any `GET`, `PATCH`, and `DELETE` requests. |
|
||||||
|
| `500 INTERNAL SERVER ERROR` | When things go horribly wrong. Should never occur. |
|
||||||
|
|
||||||
|
|
||||||
|
Error Objects:
|
||||||
|
|
||||||
|
See https://jsonapi.org/format/#errors
|
||||||
|
|
||||||
|
`400 BAD REQUEST` - _Collection_ of error objects.
|
||||||
|
|
||||||
|
_Validation Errors - Username_
|
||||||
|
|
||||||
|
| attribute | type | description/value |
|
||||||
|
| ------ | ------ | ------ |
|
||||||
|
| id | string | base62 url-safe uuid |
|
||||||
|
| title | string | Human readable title for the error. Many errors may share this title. |
|
||||||
|
| description | string | Human readable description for _this instance_ of the problem. |
|
||||||
|
| status | string | `422` |
|
||||||
|
| code | string | base62 resource id of constraint which failed |
|
||||||
|
| source | object | |
|
||||||
|
| pointer |string| `/data/attributes/username`|
|
||||||
|
| meta | map| `accessibilityDescription` = Screen reader compatible description |
|
||||||
|
| | | ?? |
|
||||||
|
|
||||||
|
_Validation Errors - Password_
|
||||||
|
|
||||||
|
| attribute | type | description/value |
|
||||||
|
| ------ | ------ | ------ |
|
||||||
|
| id | string | base62 url-safe uuid |
|
||||||
|
| title | string | Human readable title for the error. Many errors may share this title. |
|
||||||
|
| description | string | Human readable description for _this instance_ of the problem. |
|
||||||
|
| status | string | `422` |
|
||||||
|
| code | string | base62 resource id of constraint which failed |
|
||||||
|
| source | object | |
|
||||||
|
| pointer |string| `/data/attributes/password`|
|
||||||
|
| meta | map| `accessibilityDescription` = Screen reader compatible description |
|
||||||
|
| | | ?? |
|
||||||
|
|
||||||
|
|
||||||
|
`405 METHOD NOT ALLOWED` - Single error object.
|
||||||
|
|
||||||
|
| attribute | type | description/value |
|
||||||
|
| ------ | ------ | ------ |
|
||||||
|
| id | string | base62 url-safe uuid |
|
||||||
|
| title | string | Human readable title for the error. |
|
||||||
|
| status | string | `405` |
|
||||||
|
|
||||||
|
|
||||||
|
`500 INTERNAL SERVER ERRORD` - Single error object.
|
||||||
|
|
||||||
|
| attribute | type | description/value |
|
||||||
|
| ------ | ------ | ------ |
|
||||||
|
| id | string | base62 url-safe uuid |
|
||||||
|
| title | string | Human readable title for the error. |
|
||||||
|
| status | string | `500` |
|
||||||
|
|
||||||
140
pom.xml
Normal file
140
pom.xml
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
Copyright 2021-2022 John Groller
|
||||||
|
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.jkgroller</groupId>
|
||||||
|
<artifactId>validation-authority</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>Validation Authority API</name>
|
||||||
|
<description>Provides resources used for rule-based validation and generation.</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.3.2.RELEASE</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
<java.version>8</java.version>
|
||||||
|
<commons.lang3.version>3.5</commons.lang3.version>
|
||||||
|
<crnk.version>3.2.20200419165537</crnk.version>
|
||||||
|
<commons.io.version>2.5</commons.io.version>
|
||||||
|
<mapstruct.version>1.3.1.Final</mapstruct.version>
|
||||||
|
<passay.version>1.6.0</passay.version>
|
||||||
|
<mycila.license.version>4.0.rc1</mycila.license.version>
|
||||||
|
<friendly.id.version>1.1.0</friendly.id.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>JCenter</id>
|
||||||
|
<url>https://jcenter.bintray.com/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-devtools</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-io</groupId>
|
||||||
|
<artifactId>commons-io</artifactId>
|
||||||
|
<version>${commons.io.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>${commons.lang3.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.crnk</groupId>
|
||||||
|
<artifactId>crnk-setup-spring-boot2</artifactId>
|
||||||
|
<version>${crnk.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct</artifactId>
|
||||||
|
<version>${mapstruct.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.devskiller.friendly-id</groupId>
|
||||||
|
<artifactId>friendly-id</artifactId>
|
||||||
|
<version>${friendly.id.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.passay</groupId>
|
||||||
|
<artifactId>passay</artifactId>
|
||||||
|
<version>${passay.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-codec</groupId>
|
||||||
|
<artifactId>commons-codec</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>ValidationAuthority</finalName>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<annotationProcessorPaths>
|
||||||
|
<path>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct-processor</artifactId>
|
||||||
|
<version>${mapstruct.version}</version>
|
||||||
|
</path>
|
||||||
|
</annotationProcessorPaths>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.mycila</groupId>
|
||||||
|
<artifactId>license-maven-plugin</artifactId>
|
||||||
|
<version>${mycila.license.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<licenseSets>
|
||||||
|
<licenseSet>
|
||||||
|
<header>src/main/resources/licenseTemplate.txt</header>
|
||||||
|
<excludes>
|
||||||
|
<exclude>**/README</exclude>
|
||||||
|
<exclude>src/test/resources/**</exclude>
|
||||||
|
<exclude>src/main/resources/**</exclude>
|
||||||
|
</excludes>
|
||||||
|
</licenseSet>
|
||||||
|
</licenseSets>
|
||||||
|
<properties>
|
||||||
|
<owner>John Groller</owner>
|
||||||
|
</properties>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>check</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* API providing validation resources.
|
||||||
|
*/
|
||||||
|
@SpringBootApplication
|
||||||
|
public class ValidationAuthority {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start it up.
|
||||||
|
*
|
||||||
|
* @param args
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(ValidationAuthority.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,259 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.config;
|
||||||
|
|
||||||
|
import com.jkgroller.validationauthority.constraints.password.*;
|
||||||
|
import com.jkgroller.validationauthority.constraints.username.UsernameEmailSubstringConstraint;
|
||||||
|
import com.jkgroller.validationauthority.constraints.username.UsernameLeadingTrailingSpaceConstraint;
|
||||||
|
import com.jkgroller.validationauthority.constraints.username.UsernameLengthConstraint;
|
||||||
|
import com.jkgroller.validationauthority.resource.CredentialRuleResource;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loading up the rule resources for use in the UI. Could be externalized.
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class CredentialRulesConfig {
|
||||||
|
|
||||||
|
@Value("${password.validation.minimumLength}")
|
||||||
|
private int passwordMinimumLength;
|
||||||
|
|
||||||
|
@Value("${password.validation.maximumLength}")
|
||||||
|
private int passwordMaximumLength;
|
||||||
|
|
||||||
|
@Value("${username.validation.minimumLength}")
|
||||||
|
private int usernameMinimumLength;
|
||||||
|
|
||||||
|
@Value("${username.validation.maximumLength}")
|
||||||
|
private int usernameMaximumLength;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the bean.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Bean(name = "credentialRuleResources")
|
||||||
|
public List<CredentialRuleResource> createCredentialRuleResources() {
|
||||||
|
|
||||||
|
List<CredentialRuleResource> CredentialRuleResources = new ArrayList<CredentialRuleResource>();
|
||||||
|
|
||||||
|
CredentialRuleResources.add(createPasswordPrintableAsciiCharactersRuleResource());
|
||||||
|
CredentialRuleResources.add(createPasswordLengthRuleResource());
|
||||||
|
CredentialRuleResources.add(createPasswordSpecialCharacterRuleResource());
|
||||||
|
CredentialRuleResources.add(createPasswordEmailForbiddenRuleResource());
|
||||||
|
CredentialRuleResources.add(createPasswordUsernameForbiddenRuleResource());
|
||||||
|
CredentialRuleResources.add(createUsernamePrintableAsciiCharactersRuleResource());
|
||||||
|
CredentialRuleResources.add(createUsernameLengthRuleResource());
|
||||||
|
CredentialRuleResources.add(createUsernameEmailForbiddenRuleResource());
|
||||||
|
CredentialRuleResources.add(createUsernameLeadingTrailingSpacesRuleResource());
|
||||||
|
|
||||||
|
return CredentialRuleResources;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create password printable ascii character rules.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private CredentialRuleResource createPasswordPrintableAsciiCharactersRuleResource() {
|
||||||
|
|
||||||
|
CredentialRuleResource passwordPrintableAsciiCharactersRuleResource = new CredentialRuleResource();
|
||||||
|
|
||||||
|
passwordPrintableAsciiCharactersRuleResource.setId("2Znw1zI46fXgYisLoi9hF8");
|
||||||
|
passwordPrintableAsciiCharactersRuleResource.setCode(PasswordEnglishAllowedCharacterConstraint.CODE);
|
||||||
|
passwordPrintableAsciiCharactersRuleResource
|
||||||
|
.setDescription("Only standard English keyboard characters " + "allowed");
|
||||||
|
passwordPrintableAsciiCharactersRuleResource
|
||||||
|
.setAriaDescription("Only standard English keyboard characters " + "allowed");
|
||||||
|
passwordPrintableAsciiCharactersRuleResource.setExplicit(true);
|
||||||
|
passwordPrintableAsciiCharactersRuleResource.setAppliesTo("password");
|
||||||
|
|
||||||
|
return passwordPrintableAsciiCharactersRuleResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create password length rule.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private CredentialRuleResource createPasswordLengthRuleResource() {
|
||||||
|
|
||||||
|
CredentialRuleResource passwordLengthRuleResource = new CredentialRuleResource();
|
||||||
|
|
||||||
|
passwordLengthRuleResource.setId("6USKQgPUolT95cSLTtqC5v");
|
||||||
|
passwordLengthRuleResource.setCode(PasswordLengthConstraint.CODE);
|
||||||
|
passwordLengthRuleResource.setDescription("CHARACTERS");
|
||||||
|
passwordLengthRuleResource.setAriaDescription(
|
||||||
|
"Must be between " + passwordMinimumLength + " and " + passwordMaximumLength + " characters long");
|
||||||
|
passwordLengthRuleResource.setExplicit(true);
|
||||||
|
passwordLengthRuleResource.setImageType("text");
|
||||||
|
passwordLengthRuleResource.setImage("12+");
|
||||||
|
passwordLengthRuleResource.setAppliesTo("password");
|
||||||
|
|
||||||
|
return passwordLengthRuleResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create special characters rule.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private CredentialRuleResource createPasswordSpecialCharacterRuleResource() {
|
||||||
|
|
||||||
|
CredentialRuleResource passwordSpecialCharacterRuleResource = new CredentialRuleResource();
|
||||||
|
|
||||||
|
passwordSpecialCharacterRuleResource.setId("6QVdke9thuBFxyzUxo6JjL");
|
||||||
|
passwordSpecialCharacterRuleResource.setCode(PasswordSpecialCharacterConstraint.CODE);
|
||||||
|
passwordSpecialCharacterRuleResource.setDescription("ANY SPECIAL CHARACTERS");
|
||||||
|
passwordSpecialCharacterRuleResource
|
||||||
|
.setAriaDescription("Must contain at least one non alpha numeric special " + "character");
|
||||||
|
passwordSpecialCharacterRuleResource.setExplicit(true);
|
||||||
|
passwordSpecialCharacterRuleResource.setImageType("text");
|
||||||
|
passwordSpecialCharacterRuleResource.setImage("1+");
|
||||||
|
passwordSpecialCharacterRuleResource.setAppliesTo("password");
|
||||||
|
|
||||||
|
return passwordSpecialCharacterRuleResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create password email forbidden rule.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
private CredentialRuleResource createPasswordEmailForbiddenRuleResource() {
|
||||||
|
|
||||||
|
CredentialRuleResource passwordEmailForbiddenRuleResource = new CredentialRuleResource();
|
||||||
|
|
||||||
|
passwordEmailForbiddenRuleResource.setId("3qs3IwQB01YIehyDZOwpuc");
|
||||||
|
passwordEmailForbiddenRuleResource.setCode(PasswordEmailSubstringConstraint.CODE);
|
||||||
|
passwordEmailForbiddenRuleResource.setDescription("EMAIL NOT ALLOWED");
|
||||||
|
passwordEmailForbiddenRuleResource.setAriaDescription("Must not contain email address");
|
||||||
|
passwordEmailForbiddenRuleResource.setExplicit(true);
|
||||||
|
passwordEmailForbiddenRuleResource.setImageType("icon");
|
||||||
|
passwordEmailForbiddenRuleResource.setImage("email");
|
||||||
|
passwordEmailForbiddenRuleResource.setAppliesTo("password");
|
||||||
|
passwordEmailForbiddenRuleResource.setModifiers(new ArrayList<String>() {
|
||||||
|
{
|
||||||
|
add("i");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return passwordEmailForbiddenRuleResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create password username forbidden rule.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private CredentialRuleResource createPasswordUsernameForbiddenRuleResource() {
|
||||||
|
|
||||||
|
CredentialRuleResource passwordUsernameForbiddenRuleResource = new CredentialRuleResource();
|
||||||
|
|
||||||
|
passwordUsernameForbiddenRuleResource.setId("4NAFhwNcUyiNnzH2p6l8H8");
|
||||||
|
passwordUsernameForbiddenRuleResource.setCode(PasswordUsernameConstraint.CODE);
|
||||||
|
passwordUsernameForbiddenRuleResource.setDescription("USERNAME NOT ALLOWED");
|
||||||
|
passwordUsernameForbiddenRuleResource.setAriaDescription("Must not contain user name");
|
||||||
|
passwordUsernameForbiddenRuleResource.setExplicit(false);
|
||||||
|
passwordUsernameForbiddenRuleResource.setAppliesTo("password");
|
||||||
|
|
||||||
|
return passwordUsernameForbiddenRuleResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create username printable ascii characters rule.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private CredentialRuleResource createUsernamePrintableAsciiCharactersRuleResource() {
|
||||||
|
|
||||||
|
CredentialRuleResource usernamePrintableAsciiCharactersRuleResource = new CredentialRuleResource();
|
||||||
|
|
||||||
|
usernamePrintableAsciiCharactersRuleResource.setId("5Wq2qfgtjZfppaAHXy1EQJ");
|
||||||
|
usernamePrintableAsciiCharactersRuleResource.setCode(UsernameEmailSubstringConstraint.CODE);
|
||||||
|
usernamePrintableAsciiCharactersRuleResource
|
||||||
|
.setDescription("Only standard English keyboard characters " + "allowed");
|
||||||
|
usernamePrintableAsciiCharactersRuleResource
|
||||||
|
.setAriaDescription(usernamePrintableAsciiCharactersRuleResource.getDescription());
|
||||||
|
usernamePrintableAsciiCharactersRuleResource.setExplicit(true);
|
||||||
|
usernamePrintableAsciiCharactersRuleResource.setAppliesTo("username");
|
||||||
|
|
||||||
|
return usernamePrintableAsciiCharactersRuleResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create username length rule.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private CredentialRuleResource createUsernameLengthRuleResource() {
|
||||||
|
|
||||||
|
CredentialRuleResource usernameLengthRuleResource = new CredentialRuleResource();
|
||||||
|
|
||||||
|
usernameLengthRuleResource.setId("SUEVxQKsWeWJTH6ESFr9m");
|
||||||
|
usernameLengthRuleResource.setCode(UsernameLengthConstraint.CODE);
|
||||||
|
usernameLengthRuleResource.setDescription("CHARACTERS");
|
||||||
|
usernameLengthRuleResource.setAriaDescription(
|
||||||
|
"Must be between " + usernameMinimumLength + " and " + usernameMaximumLength + "characters long");
|
||||||
|
usernameLengthRuleResource.setExplicit(true);
|
||||||
|
usernameLengthRuleResource.setImageType("text");
|
||||||
|
usernameLengthRuleResource.setImage("12+");
|
||||||
|
usernameLengthRuleResource.setAppliesTo("username");
|
||||||
|
|
||||||
|
return usernameLengthRuleResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create username email forbidden rule.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private CredentialRuleResource createUsernameEmailForbiddenRuleResource() {
|
||||||
|
|
||||||
|
CredentialRuleResource usernameEmailForbiddenRuleResource = new CredentialRuleResource();
|
||||||
|
List<String> modifiers = new ArrayList<String>() {
|
||||||
|
{
|
||||||
|
add("i");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
usernameEmailForbiddenRuleResource.setId("A4dwWPFdAgWSzw2rew3MK");
|
||||||
|
usernameEmailForbiddenRuleResource.setCode(UsernameEmailSubstringConstraint.CODE);
|
||||||
|
usernameEmailForbiddenRuleResource.setDescription("EMAIL NOT ALLOWED");
|
||||||
|
usernameEmailForbiddenRuleResource.setAriaDescription("Must not contain email address");
|
||||||
|
usernameEmailForbiddenRuleResource.setExplicit(true);
|
||||||
|
usernameEmailForbiddenRuleResource.setImageType("icon");
|
||||||
|
usernameEmailForbiddenRuleResource.setImage("email");
|
||||||
|
usernameEmailForbiddenRuleResource.setModifiers(modifiers);
|
||||||
|
usernameEmailForbiddenRuleResource.setAppliesTo("username");
|
||||||
|
|
||||||
|
return usernameEmailForbiddenRuleResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create username leading trailing spaces rule.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private CredentialRuleResource createUsernameLeadingTrailingSpacesRuleResource() {
|
||||||
|
|
||||||
|
CredentialRuleResource usernameLeadingTrailingSpacesRuleResource = new CredentialRuleResource();
|
||||||
|
|
||||||
|
usernameLeadingTrailingSpacesRuleResource.setId("6Ej8sla6VSmbnaIV7wJ8mm");
|
||||||
|
usernameLeadingTrailingSpacesRuleResource.setCode(UsernameLeadingTrailingSpaceConstraint.CODE);
|
||||||
|
usernameLeadingTrailingSpacesRuleResource.setDescription("Username may not begin or end with spaces");
|
||||||
|
usernameLeadingTrailingSpacesRuleResource.setAriaDescription("OUsername may not begin or end with spaces");
|
||||||
|
usernameLeadingTrailingSpacesRuleResource.setExplicit(true);
|
||||||
|
usernameLeadingTrailingSpacesRuleResource.setAppliesTo("username");
|
||||||
|
|
||||||
|
return usernameLeadingTrailingSpacesRuleResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.constraints.password;
|
||||||
|
|
||||||
|
import com.jkgroller.validationauthority.resource.CredentialsResource;
|
||||||
|
import io.crnk.core.engine.document.ErrorData;
|
||||||
|
import io.crnk.core.engine.http.HttpStatus;
|
||||||
|
import org.passay.IllegalRegexRule;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Class for building the email substring rule. If an email is detected,
|
||||||
|
* validation fails.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class PasswordEmailSubstringConstraint extends IllegalRegexRule {
|
||||||
|
|
||||||
|
public static final String HTTP_STATUS = Integer.toString(HttpStatus.UNPROCESSABLE_ENTITY_422);
|
||||||
|
|
||||||
|
public static final String CODE = "8388";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the regex to find email addresses.
|
||||||
|
*/
|
||||||
|
public PasswordEmailSubstringConstraint(@Value("${regex.emailAddressSubstring}") String emailRegex) {
|
||||||
|
super(emailRegex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to generate the error object for this rule failure.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ErrorData getErrorData() {
|
||||||
|
|
||||||
|
return ErrorData.builder().setTitle("Password substring failure")
|
||||||
|
.setDetail("Password must not contain email address.")
|
||||||
|
.setSourcePointer(CredentialsResource.SOURCE_POINTER_PASSWORD).setStatus(HTTP_STATUS).setCode(CODE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.constraints.password;
|
||||||
|
|
||||||
|
import com.jkgroller.validationauthority.resource.CredentialsResource;
|
||||||
|
import io.crnk.core.engine.document.ErrorData;
|
||||||
|
import io.crnk.core.engine.http.HttpStatus;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.passay.AllowedCharacterRule;
|
||||||
|
import org.passay.EnglishCharacterData;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Provides the allowed character rule... allowing all English
|
||||||
|
* characters.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class PasswordEnglishAllowedCharacterConstraint extends AllowedCharacterRule {
|
||||||
|
|
||||||
|
public static final String CODE = "7257";
|
||||||
|
|
||||||
|
public static String HTTP_STATUS = Integer.toString(HttpStatus.UNPROCESSABLE_ENTITY_422);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All English characters allowed.
|
||||||
|
*/
|
||||||
|
public PasswordEnglishAllowedCharacterConstraint() {
|
||||||
|
|
||||||
|
super((EnglishCharacterData.Alphabetical.getCharacters() + EnglishCharacterData.Digit.getCharacters()
|
||||||
|
+ StringUtils.SPACE + EnglishCharacterData.Special.getCharacters()).toCharArray());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to generate the error object for this rule failure.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ErrorData getErrorData() {
|
||||||
|
|
||||||
|
return ErrorData.builder().setTitle("Character set validation failure.")
|
||||||
|
.setDetail("Password must contain only English characters.")
|
||||||
|
.setSourcePointer(CredentialsResource.SOURCE_POINTER_PASSWORD).setStatus(HTTP_STATUS).setCode(CODE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.constraints.password;
|
||||||
|
|
||||||
|
import com.jkgroller.validationauthority.resource.CredentialsResource;
|
||||||
|
import io.crnk.core.engine.document.ErrorData;
|
||||||
|
import io.crnk.core.engine.http.HttpStatus;
|
||||||
|
import org.passay.LengthRule;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Provides the length rule for passwords.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class PasswordLengthConstraint extends LengthRule {
|
||||||
|
|
||||||
|
public static String HTTP_STATUS = Integer.toString(HttpStatus.UNPROCESSABLE_ENTITY_422);
|
||||||
|
|
||||||
|
public static String CODE = "2736";
|
||||||
|
|
||||||
|
@Value("${password.validation.minimumLength}")
|
||||||
|
private int minimumLength;
|
||||||
|
|
||||||
|
@Value("${password.validation.maximumLength}")
|
||||||
|
private int maximumLength;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimum length of minimumLength, and max of maximumLength
|
||||||
|
*/
|
||||||
|
public PasswordLengthConstraint(@Value("${password.validation.minimumLength}") int minimumLength,
|
||||||
|
@Value("${password.validation.maximumLength}") int maximumLength) {
|
||||||
|
super(minimumLength, maximumLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to generate the error object for this rule failure.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ErrorData getErrorData() {
|
||||||
|
|
||||||
|
return ErrorData.builder().setTitle("Invalid password length.")
|
||||||
|
.setDetail("Password must be between " + minimumLength + " and " + maximumLength + " characters long" +
|
||||||
|
".").setSourcePointer(CredentialsResource.SOURCE_POINTER_PASSWORD)
|
||||||
|
.setStatus(HTTP_STATUS).setCode(CODE).build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.constraints.password;
|
||||||
|
|
||||||
|
import com.jkgroller.validationauthority.resource.CredentialsResource;
|
||||||
|
import io.crnk.core.engine.document.ErrorData;
|
||||||
|
import io.crnk.core.engine.http.HttpStatus;
|
||||||
|
import org.passay.CharacterRule;
|
||||||
|
import org.passay.EnglishCharacterData;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Provides the rule regarding special characters.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class PasswordSpecialCharacterConstraint extends CharacterRule {
|
||||||
|
|
||||||
|
public static final String ERROR_CODE = "INSUFFICIENT_SPECIAL";
|
||||||
|
|
||||||
|
public static final String HTTP_STATUS = Integer.toString(HttpStatus.UNPROCESSABLE_ENTITY_422);
|
||||||
|
|
||||||
|
public static final String CODE = "4959";
|
||||||
|
|
||||||
|
@Value("${password.validation.numberOfSpecialCharacters}")
|
||||||
|
private int numberOfSpecialCharacters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One English special character required.
|
||||||
|
*/
|
||||||
|
public PasswordSpecialCharacterConstraint(
|
||||||
|
@Value("${password.validation.numberOfSpecialCharacters}") int numberOfSpecialCharacters) {
|
||||||
|
super(EnglishCharacterData.Special, numberOfSpecialCharacters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to generate the error object for this rule failure.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ErrorData getErrorData() {
|
||||||
|
|
||||||
|
return ErrorData.builder().setTitle("Password does not meet character requirements.")
|
||||||
|
.setDetail("Password must contain " + numberOfSpecialCharacters + " special character.")
|
||||||
|
.setSourcePointer(CredentialsResource.SOURCE_POINTER_USERNAME).setStatus(HTTP_STATUS).setCode(CODE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.constraints.password;
|
||||||
|
|
||||||
|
import com.jkgroller.validationauthority.resource.CredentialsResource;
|
||||||
|
import io.crnk.core.engine.document.ErrorData;
|
||||||
|
import io.crnk.core.engine.http.HttpStatus;
|
||||||
|
import org.passay.MatchBehavior;
|
||||||
|
import org.passay.UsernameRule;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Applies the behavior for detecting how to detect username in
|
||||||
|
* password.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class PasswordUsernameConstraint extends UsernameRule {
|
||||||
|
|
||||||
|
public static String HTTP_STATUS = Integer.toString(HttpStatus.UNPROCESSABLE_ENTITY_422);
|
||||||
|
|
||||||
|
public static String CODE = "4690";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checking if password contains username.
|
||||||
|
*/
|
||||||
|
public PasswordUsernameConstraint() {
|
||||||
|
super(MatchBehavior.Contains);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to generate the error object for this rule failure.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ErrorData getErrorData() {
|
||||||
|
|
||||||
|
return ErrorData.builder()
|
||||||
|
.setTitle("Password contains an invalid pattern.").setDetail("Password must not contain a username.")
|
||||||
|
.setSourcePointer(CredentialsResource.SOURCE_POINTER_PASSWORD).setStatus(HTTP_STATUS).setCode(CODE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.constraints.username;
|
||||||
|
|
||||||
|
import com.jkgroller.validationauthority.resource.CredentialsResource;
|
||||||
|
import io.crnk.core.engine.document.ErrorData;
|
||||||
|
import io.crnk.core.engine.http.HttpStatus;
|
||||||
|
import org.passay.IllegalRegexRule;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Class for building the email substring rule. If an email is detected,
|
||||||
|
* validation fails.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class UsernameEmailSubstringConstraint extends IllegalRegexRule {
|
||||||
|
|
||||||
|
public static final String HTTP_STATUS = Integer.toString(HttpStatus.UNPROCESSABLE_ENTITY_422);
|
||||||
|
|
||||||
|
public static final String CODE = "3589";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the regex to find email addresses.
|
||||||
|
*/
|
||||||
|
public UsernameEmailSubstringConstraint(@Value("${regex.emailAddressSubstring}") String emailRegex) {
|
||||||
|
super(emailRegex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to generate the error object for this rule failure.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ErrorData getErrorData() {
|
||||||
|
|
||||||
|
return ErrorData.builder()
|
||||||
|
.setTitle("Username contains an invalid pattern.")
|
||||||
|
.setDetail("Username must not contain an email address.")
|
||||||
|
.setSourcePointer(CredentialsResource.SOURCE_POINTER_USERNAME).setStatus(HTTP_STATUS).setCode(CODE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.constraints.username;
|
||||||
|
|
||||||
|
import com.jkgroller.validationauthority.resource.CredentialsResource;
|
||||||
|
import io.crnk.core.engine.document.ErrorData;
|
||||||
|
import io.crnk.core.engine.http.HttpStatus;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.passay.AllowedCharacterRule;
|
||||||
|
import org.passay.EnglishCharacterData;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Provides the allowed character rule... allowing all English
|
||||||
|
* characters.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class UsernameEnglishAllowedCharacterConstraint extends AllowedCharacterRule {
|
||||||
|
|
||||||
|
public static final String HTTP_STATUS = Integer.toString(HttpStatus.UNPROCESSABLE_ENTITY_422);
|
||||||
|
|
||||||
|
public static final String CODE = "3365";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All English characters allowed.
|
||||||
|
*/
|
||||||
|
public UsernameEnglishAllowedCharacterConstraint() {
|
||||||
|
|
||||||
|
super((EnglishCharacterData.Alphabetical.getCharacters() + EnglishCharacterData.Digit.getCharacters()
|
||||||
|
+ StringUtils.SPACE + EnglishCharacterData.Special.getCharacters()).toCharArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to generate the error object for this rule failure.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ErrorData getErrorData() {
|
||||||
|
|
||||||
|
return ErrorData.builder().setTitle("Username does not meet character requirements.")
|
||||||
|
.setDetail("Username may only contain English keyboard characters.")
|
||||||
|
.setSourcePointer(CredentialsResource.SOURCE_POINTER_USERNAME).setStatus(HTTP_STATUS).setCode(CODE)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.constraints.username;
|
||||||
|
|
||||||
|
import com.jkgroller.validationauthority.resource.CredentialsResource;
|
||||||
|
import io.crnk.core.engine.document.ErrorData;
|
||||||
|
import io.crnk.core.engine.http.HttpStatus;
|
||||||
|
import org.passay.IllegalRegexRule;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Rule for checking leading and trailing spaces for username.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class UsernameLeadingTrailingSpaceConstraint extends IllegalRegexRule {
|
||||||
|
|
||||||
|
public static final String HTTP_STATUS = Integer.toString(HttpStatus.UNPROCESSABLE_ENTITY_422);
|
||||||
|
|
||||||
|
public static final String CODE = "0316";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No leading/trailing spaces constraint.
|
||||||
|
*
|
||||||
|
* @param leadingTrailingRegex
|
||||||
|
*/
|
||||||
|
public UsernameLeadingTrailingSpaceConstraint(
|
||||||
|
@Value("${regex.leadingTrailingSpaces}") String leadingTrailingRegex) {
|
||||||
|
super(leadingTrailingRegex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Used to generate the error object for this rule failure.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ErrorData getErrorData() {
|
||||||
|
|
||||||
|
return ErrorData.builder()
|
||||||
|
.setTitle("Username contains an invalid pattern.")
|
||||||
|
.setDetail("Username must not contain leading or trailing spaces.")
|
||||||
|
.setSourcePointer(CredentialsResource.SOURCE_POINTER_USERNAME).setStatus(HTTP_STATUS).setCode(CODE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.constraints.username;
|
||||||
|
|
||||||
|
import com.jkgroller.validationauthority.resource.CredentialsResource;
|
||||||
|
import io.crnk.core.engine.document.ErrorData;
|
||||||
|
import io.crnk.core.engine.http.HttpStatus;
|
||||||
|
import org.passay.LengthRule;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Provides the length rule for usernames.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class UsernameLengthConstraint extends LengthRule {
|
||||||
|
|
||||||
|
public final String HTTP_STATUS = Integer.toString(HttpStatus.UNPROCESSABLE_ENTITY_422);
|
||||||
|
|
||||||
|
public static final String CODE = "9377";
|
||||||
|
|
||||||
|
@Value("${username.validation.minimumLength}")
|
||||||
|
private int minimumLength;
|
||||||
|
|
||||||
|
@Value("${username.validation.maximumLength}")
|
||||||
|
private int maximumLength;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimum length of minimumLength, maximum of maximumLength.
|
||||||
|
*/
|
||||||
|
public UsernameLengthConstraint(@Value("${username.validation.minimumLength}") int minimumLength,
|
||||||
|
@Value("${username.validation.maximumLength}") int maximumLength) {
|
||||||
|
|
||||||
|
super(minimumLength, maximumLength);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to generate the error object for this rule failure.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ErrorData getErrorData() {
|
||||||
|
|
||||||
|
return ErrorData.builder()
|
||||||
|
.setTitle("Invalid username length.")
|
||||||
|
.setDetail("Username must be between " + minimumLength + " and " + maximumLength + " characters " +
|
||||||
|
"long.").setSourcePointer(CredentialsResource.SOURCE_POINTER_USERNAME)
|
||||||
|
.setStatus(HTTP_STATUS).setCode(CODE).build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.converter;
|
||||||
|
|
||||||
|
import com.jkgroller.validationauthority.resource.CredentialsResource;
|
||||||
|
import com.jkgroller.validationauthority.service.to.ValidateCredentialRequestTO;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.NullValuePropertyMappingStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Uses the Mapstruct library for mapping objects.
|
||||||
|
*/
|
||||||
|
@Mapper(componentModel = "spring")
|
||||||
|
public interface ResourceConverter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param credentialsResource
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Mapping(target = "username", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT)
|
||||||
|
ValidateCredentialRequestTO credentialsResourceToValidateUsernameRequestTO(
|
||||||
|
CredentialsResource credentialsResource);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.enums;
|
||||||
|
|
||||||
|
import org.passay.CharacterData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Enum for qwerty special characters. Not sure this is necessary anymore. It was originally to
|
||||||
|
* limit special characters to the ones listed below... but it's probably fine to use all the special
|
||||||
|
* characters specified by Passay.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum CommonQwertySpecialCharactersCharacterData implements CharacterData {
|
||||||
|
|
||||||
|
CommonQwertySpecial("INSUFFICIENT_COMMON_QWERTY_SPECIAL", "!@#$%&?");
|
||||||
|
|
||||||
|
private final String errorCode;
|
||||||
|
private final String characters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param code
|
||||||
|
* @param charString
|
||||||
|
*/
|
||||||
|
CommonQwertySpecialCharactersCharacterData(String code, String charString) {
|
||||||
|
this.errorCode = code;
|
||||||
|
this.characters = charString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getErrorCode() {
|
||||||
|
return this.errorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getCharacters() {
|
||||||
|
return this.characters;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.exception;
|
||||||
|
|
||||||
|
import io.crnk.core.engine.document.ErrorData;
|
||||||
|
import io.crnk.core.engine.http.HttpStatus;
|
||||||
|
import io.crnk.core.exception.CrnkMappableException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Custom MethodNotAllowedException
|
||||||
|
*/
|
||||||
|
public final class MethodNotAllowedException extends CrnkMappableException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = -3039598962652245954L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param message
|
||||||
|
*/
|
||||||
|
public MethodNotAllowedException(String message) {
|
||||||
|
super(HttpStatus.METHOD_NOT_ALLOWED_405, ErrorData.builder().setTitle(message)
|
||||||
|
.setStatus(Integer.toString(HttpStatus.METHOD_NOT_ALLOWED_405)).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.exception;
|
||||||
|
|
||||||
|
import io.crnk.core.engine.document.ErrorData;
|
||||||
|
import io.crnk.core.engine.http.HttpStatus;
|
||||||
|
import io.crnk.core.exception.CrnkMappableException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Custom NotImplementedException
|
||||||
|
*/
|
||||||
|
public final class NotImplementedException extends CrnkMappableException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 6988134119651781248L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param message
|
||||||
|
*/
|
||||||
|
public NotImplementedException(String message) {
|
||||||
|
super(HttpStatus.NOT_IMPLEMENTED_501, ErrorData.builder().setTitle(message)
|
||||||
|
.setStatus(Integer.toString(HttpStatus.NOT_IMPLEMENTED_501)).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.exception;
|
||||||
|
|
||||||
|
import io.crnk.core.engine.document.ErrorData;
|
||||||
|
import io.crnk.core.engine.http.HttpStatus;
|
||||||
|
import io.crnk.core.exception.CrnkMappableException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @Author john@grollerfamily.com Custom ResourceNotFoundException, for when resource for a type
|
||||||
|
* cannot be found.
|
||||||
|
*/
|
||||||
|
public final class ResourceNotFoundException extends CrnkMappableException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 5747890979256007262L;
|
||||||
|
|
||||||
|
public ResourceNotFoundException(String message) {
|
||||||
|
super(HttpStatus.NOT_FOUND_404,
|
||||||
|
ErrorData.builder().setTitle(message).setStatus(Integer.toString(HttpStatus.NOT_FOUND_404)).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.exception;
|
||||||
|
|
||||||
|
import io.crnk.core.engine.document.ErrorData;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Custom ValidationFailedException for the overall failure of
|
||||||
|
* validations.
|
||||||
|
*/
|
||||||
|
public class ValidationFailedException extends RuntimeException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = -7873709164154851376L;
|
||||||
|
private List<ErrorData> errors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new runtime exception with the specified detail message. The
|
||||||
|
* cause is not initialized, and may subsequently be initialized by a call to
|
||||||
|
* {@link #initCause}.
|
||||||
|
*
|
||||||
|
* @param message the detail message. The detail message is saved for later
|
||||||
|
* retrieval by the {@link #getMessage()} method.
|
||||||
|
*/
|
||||||
|
public ValidationFailedException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new runtime exception with {@code null} as its detail message.
|
||||||
|
* The cause is not initialized, and may subsequently be initialized by a call
|
||||||
|
* to {@link #initCause}.
|
||||||
|
*/
|
||||||
|
public ValidationFailedException(List<ErrorData> errors) {
|
||||||
|
this.errors = errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<ErrorData> getErrors() {
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.exception.mapper;
|
||||||
|
|
||||||
|
import com.jkgroller.validationauthority.exception.ValidationFailedException;
|
||||||
|
import io.crnk.core.engine.document.ErrorData;
|
||||||
|
import io.crnk.core.engine.error.ErrorResponse;
|
||||||
|
import io.crnk.core.engine.error.ExceptionMapper;
|
||||||
|
import io.crnk.core.engine.http.HttpStatus;
|
||||||
|
import io.crnk.core.repository.response.JsonApiResponse;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Overall validation failed exception which maps all the validation errors for the failure collection.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class ValidationFailedExceptionMapper implements ExceptionMapper<ValidationFailedException> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the given exception to an JSON API response. Used on the server-side.
|
||||||
|
*
|
||||||
|
* @param exception
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ErrorResponse toErrorResponse(ValidationFailedException exception) {
|
||||||
|
return ErrorResponse.builder().setStatus(HttpStatus.BAD_REQUEST_400).setErrorData(exception.getErrors()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the given error response to an exception. Used on the client-side.
|
||||||
|
*
|
||||||
|
* @param errorResponse error response
|
||||||
|
* @return exception
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ValidationFailedException fromErrorResponse(ErrorResponse errorResponse) {
|
||||||
|
JsonApiResponse response = errorResponse.getResponse();
|
||||||
|
List<ErrorData> errors = response.getErrors();
|
||||||
|
StringBuilder message = new StringBuilder();
|
||||||
|
for (ErrorData error : errors) {
|
||||||
|
String title = error.getDetail();
|
||||||
|
message.append(title);
|
||||||
|
}
|
||||||
|
return new ValidationFailedException(message.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decides whether the given errorResponse can be handled by this mapper.
|
||||||
|
* If true is returned, {@link #fromErrorResponse(ErrorResponse)} will be called.
|
||||||
|
* <p>
|
||||||
|
* If multiple mappers accept a given error response, the most specific exception is chosen, meaning
|
||||||
|
* the one with the most superTypes.
|
||||||
|
*
|
||||||
|
* @param errorResponse
|
||||||
|
* @return true if it can be handled.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean accepts(ErrorResponse errorResponse) {
|
||||||
|
return HttpStatus.UNPROCESSABLE_ENTITY_422 == errorResponse.getHttpStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.resource;
|
||||||
|
|
||||||
|
import io.crnk.core.resource.annotations.JsonApiId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* All resources in this API follow JSON:API and are required to have an id attribute.
|
||||||
|
*/
|
||||||
|
public class BaseResource {
|
||||||
|
|
||||||
|
// Identifier required by the JSON:API spec
|
||||||
|
@JsonApiId
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.resource;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* All rules tend to have the same attributes.
|
||||||
|
*/
|
||||||
|
public class BaseRuleResource extends BaseResource {
|
||||||
|
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
private String appliesTo;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
private String ariaDescription;
|
||||||
|
|
||||||
|
private List<String> modifiers;
|
||||||
|
|
||||||
|
private boolean explicit;
|
||||||
|
|
||||||
|
private String imageType;
|
||||||
|
|
||||||
|
private String image;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param code
|
||||||
|
*/
|
||||||
|
public void setCode(String code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getAppliesTo() {
|
||||||
|
return appliesTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param appliesTo
|
||||||
|
*/
|
||||||
|
public void setAppliesTo(String appliesTo) {
|
||||||
|
this.appliesTo = appliesTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param description
|
||||||
|
*/
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getAriaDescription() {
|
||||||
|
return ariaDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ariaDescription
|
||||||
|
*/
|
||||||
|
public void setAriaDescription(String ariaDescription) {
|
||||||
|
this.ariaDescription = ariaDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<String> getModifiers() {
|
||||||
|
return modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param modifiers
|
||||||
|
*/
|
||||||
|
public void setModifiers(List<String> modifiers) {
|
||||||
|
this.modifiers = modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isExplicit() {
|
||||||
|
return explicit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param explicit
|
||||||
|
*/
|
||||||
|
public void setExplicit(boolean explicit) {
|
||||||
|
this.explicit = explicit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getImageType() {
|
||||||
|
return imageType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param imageType
|
||||||
|
*/
|
||||||
|
public void setImageType(String imageType) {
|
||||||
|
this.imageType = imageType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getImage() {
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param image
|
||||||
|
*/
|
||||||
|
public void setImage(String image) {
|
||||||
|
this.image = image;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.resource;
|
||||||
|
|
||||||
|
import io.crnk.core.resource.annotations.JsonApiResource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* This class intentionally left blank.
|
||||||
|
* <p>
|
||||||
|
* It uses the attributes from the BaseRuleResource and represents them
|
||||||
|
* as a /credentialRules resource.
|
||||||
|
*/
|
||||||
|
@JsonApiResource(type = "credentialRule", resourcePath = "credentialRules")
|
||||||
|
public class CredentialRuleResource extends BaseRuleResource {
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.resource;
|
||||||
|
|
||||||
|
import io.crnk.core.resource.annotations.JsonApiField;
|
||||||
|
import io.crnk.core.resource.annotations.JsonApiResource;
|
||||||
|
|
||||||
|
@JsonApiResource(type = "credentials", resourcePath = "credentials")
|
||||||
|
public class CredentialsResource extends BaseResource {
|
||||||
|
|
||||||
|
public static final String SOURCE_POINTER_USERNAME = "/data/attributes/username";
|
||||||
|
|
||||||
|
public static final String SOURCE_POINTER_PASSWORD = "/data/attributes/password";
|
||||||
|
|
||||||
|
@JsonApiField(readable = false, postable = true, patchable = false, deletable = false)
|
||||||
|
private char[] username;
|
||||||
|
|
||||||
|
@JsonApiField(readable = false, postable = true, patchable = false, deletable = false)
|
||||||
|
private char[] password;
|
||||||
|
|
||||||
|
public char[] getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(char[] username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char[] getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(char[] password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.resource.repository;
|
||||||
|
|
||||||
|
import com.jkgroller.validationauthority.exception.MethodNotAllowedException;
|
||||||
|
import com.jkgroller.validationauthority.exception.NotImplementedException;
|
||||||
|
import com.jkgroller.validationauthority.resource.CredentialRuleResource;
|
||||||
|
import io.crnk.core.queryspec.QuerySpec;
|
||||||
|
import io.crnk.core.repository.ResourceRepository;
|
||||||
|
import io.crnk.core.resource.list.ResourceList;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Repository for handling GET/POST/PATCH/DELETE on the credential rule
|
||||||
|
* resource.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class CredentialRuleResourceRepository implements ResourceRepository<CredentialRuleResource, String> {
|
||||||
|
|
||||||
|
private final String METHOD_NOT_ALLOWED_MESSAGE = "Method is not allowed.";
|
||||||
|
|
||||||
|
private final String NOT_IMPLEMENTED_MESSAGE = "This request is currently unsupported.";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private List<CredentialRuleResource> credentialRuleResources;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crnk will blow up without this and give you the most confusing exception
|
||||||
|
* ever.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Class<CredentialRuleResource> getResourceClass() {
|
||||||
|
return CredentialRuleResource.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET requests for /v1/credentialRules/<id> will come here.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CredentialRuleResource findOne(String id, QuerySpec querySpec) {
|
||||||
|
return credentialRuleResources.stream()
|
||||||
|
.filter(credentialRuleResource -> id.equals(credentialRuleResource.getId())).findAny().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET requests for /v1/credentialRules will come here.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ResourceList<CredentialRuleResource> findAll(QuerySpec querySpec) {
|
||||||
|
return querySpec.apply(credentialRuleResources);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET requests for /v1/credentialRules/<id>,<id>,<id> will come here.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ResourceList<CredentialRuleResource> findAll(Collection<String> ids, QuerySpec querySpec) {
|
||||||
|
throw new NotImplementedException(NOT_IMPLEMENTED_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PATCH requests for /v1/credentialRules/<id> will come here. Keep in mind,
|
||||||
|
* however, that PATCH requests will first automatically perform a GET on
|
||||||
|
* /v1/credentialRules/<id> to retrieve the resource.
|
||||||
|
* <p>
|
||||||
|
* Controll will then pass to this method to update the resource with the values
|
||||||
|
* requested. Then, it's saved as you've specified.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <S extends CredentialRuleResource> S save(S resource) {
|
||||||
|
throw new MethodNotAllowedException(METHOD_NOT_ALLOWED_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST requests for /v1/credentialRules will come here.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <S extends CredentialRuleResource> S create(S resource) {
|
||||||
|
throw new MethodNotAllowedException(METHOD_NOT_ALLOWED_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DELETE requests for /v1/credentialRules/<id> will come here.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void delete(String id) {
|
||||||
|
throw new MethodNotAllowedException(METHOD_NOT_ALLOWED_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.resource.repository;
|
||||||
|
|
||||||
|
import com.devskiller.friendly_id.FriendlyId;
|
||||||
|
import com.jkgroller.validationauthority.converter.ResourceConverter;
|
||||||
|
import com.jkgroller.validationauthority.exception.MethodNotAllowedException;
|
||||||
|
import com.jkgroller.validationauthority.exception.ValidationFailedException;
|
||||||
|
import com.jkgroller.validationauthority.resource.CredentialsResource;
|
||||||
|
import com.jkgroller.validationauthority.service.ValidateCredentialService;
|
||||||
|
import com.jkgroller.validationauthority.service.to.ValidateCredentialRequestTO;
|
||||||
|
import com.jkgroller.validationauthority.service.to.ValidateCredentialResponseTO;
|
||||||
|
import io.crnk.core.queryspec.QuerySpec;
|
||||||
|
import io.crnk.core.repository.ResourceRepository;
|
||||||
|
import io.crnk.core.resource.list.ResourceList;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Repository for handling GET/POST/PATCH/DELETE on the credential
|
||||||
|
* resource.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class CredentialsResourceRepository implements ResourceRepository<CredentialsResource, String> {
|
||||||
|
|
||||||
|
private final String METHOD_NOT_ALLOWED_MESSAGE = "Method is not allowed.";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ResourceConverter resourceConverter;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ValidateCredentialService validateCredentialService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crnk will blow up without this and give you the most confusing exception
|
||||||
|
* ever.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Class<CredentialsResource> getResourceClass() {
|
||||||
|
return CredentialsResource.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET requests for /v1/credentials/<id> will come here.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CredentialsResource findOne(String id, QuerySpec querySpec) {
|
||||||
|
throw new MethodNotAllowedException(METHOD_NOT_ALLOWED_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET requests for /v1/credentialRules will come here.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ResourceList<CredentialsResource> findAll(QuerySpec querySpec) {
|
||||||
|
throw new MethodNotAllowedException(METHOD_NOT_ALLOWED_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET requests for /v1/credentials/<id>,<id>,<id> will come here.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ResourceList<CredentialsResource> findAll(Collection<String> ids, QuerySpec querySpec) {
|
||||||
|
throw new MethodNotAllowedException(METHOD_NOT_ALLOWED_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PATCH requests for /v1/credentials/<id> will come here. Keep in mind,
|
||||||
|
* however, that PATCH requests will first automatically perform a GET on
|
||||||
|
* /v1/credentials/<id> to retrieve the resource.
|
||||||
|
* <p>
|
||||||
|
* Controll will then pass to this method to update the resource with the values
|
||||||
|
* requested. Then, it's saved as you've specified.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <S extends CredentialsResource> S save(S resource) {
|
||||||
|
throw new MethodNotAllowedException(METHOD_NOT_ALLOWED_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST requests for /v1/credentials will come here.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public <S extends CredentialsResource> S create(S resource) {
|
||||||
|
|
||||||
|
ValidateCredentialRequestTO validateCredentialRequestTO = resourceConverter
|
||||||
|
.credentialsResourceToValidateUsernameRequestTO(resource);
|
||||||
|
ValidateCredentialResponseTO validateCredentialResponseTO = validateCredentialService
|
||||||
|
.validateCredential(validateCredentialRequestTO);
|
||||||
|
|
||||||
|
if (validateCredentialResponseTO.isValid()) {
|
||||||
|
resource.setId(FriendlyId.createFriendlyId());
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ValidationFailedException(validateCredentialResponseTO.getErrorData());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DELETE requests for /v1/credentials/<id> will come here.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void delete(String id) {
|
||||||
|
throw new MethodNotAllowedException(METHOD_NOT_ALLOWED_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.service;
|
||||||
|
|
||||||
|
import com.jkgroller.validationauthority.service.to.ValidateCredentialRequestTO;
|
||||||
|
import com.jkgroller.validationauthority.service.to.ValidateCredentialResponseTO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Service for validating the username.
|
||||||
|
*/
|
||||||
|
public interface ValidateCredentialService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the credentials.
|
||||||
|
*
|
||||||
|
* @param validateCredentialRequestTO
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
ValidateCredentialResponseTO validateCredential(ValidateCredentialRequestTO validateCredentialRequestTO);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,254 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.service;
|
||||||
|
|
||||||
|
import com.devskiller.friendly_id.FriendlyId;
|
||||||
|
import com.jkgroller.validationauthority.constraints.password.*;
|
||||||
|
import com.jkgroller.validationauthority.constraints.username.UsernameEmailSubstringConstraint;
|
||||||
|
import com.jkgroller.validationauthority.constraints.username.UsernameEnglishAllowedCharacterConstraint;
|
||||||
|
import com.jkgroller.validationauthority.constraints.username.UsernameLeadingTrailingSpaceConstraint;
|
||||||
|
import com.jkgroller.validationauthority.constraints.username.UsernameLengthConstraint;
|
||||||
|
import com.jkgroller.validationauthority.converter.ResourceConverter;
|
||||||
|
import com.jkgroller.validationauthority.resource.CredentialsResource;
|
||||||
|
import com.jkgroller.validationauthority.service.to.ValidateCredentialRequestTO;
|
||||||
|
import com.jkgroller.validationauthority.service.to.ValidateCredentialResponseTO;
|
||||||
|
import io.crnk.core.engine.document.ErrorData;
|
||||||
|
import org.passay.*;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Validates the credentials and responds with the results.
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class ValidateCredentialServiceImpl implements ValidateCredentialService {
|
||||||
|
|
||||||
|
@Value("${regex.emailAddressSubstring}")
|
||||||
|
private String emailAddressSubstringRegex;
|
||||||
|
|
||||||
|
@Value("${regex.leadingTrailingSpaces}")
|
||||||
|
private String leadingTrailingSpacesRegex;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UsernameEmailSubstringConstraint usernameEmailSubstringConstraint;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UsernameEnglishAllowedCharacterConstraint usernameEnglishAllowedCharacterConstraint;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UsernameLeadingTrailingSpaceConstraint usernameLeadingTrailingSpaceConstraint;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UsernameLengthConstraint usernameLengthConstraint;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PasswordEmailSubstringConstraint passwordEmailSubstringConstraint;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PasswordEnglishAllowedCharacterConstraint passwordEnglishAllowedCharacterConstraint;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PasswordLengthConstraint passwordLengthConstraint;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PasswordSpecialCharacterConstraint passwordSpecialCharacterConstraint;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PasswordUsernameConstraint passwordUsernameConstraint;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ResourceConverter resourceConverter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ValidateCredentialResponseTO validateCredential(ValidateCredentialRequestTO validateCredentialRequestTO) {
|
||||||
|
|
||||||
|
ValidateCredentialResponseTO validationResponseTO = new ValidateCredentialResponseTO();
|
||||||
|
List<ErrorData> masterErrorList = new ArrayList<ErrorData>();
|
||||||
|
|
||||||
|
masterErrorList.addAll(validateUsername(validateCredentialRequestTO));
|
||||||
|
masterErrorList.addAll(validatePassword(validateCredentialRequestTO));
|
||||||
|
|
||||||
|
validationResponseTO.setErrorData(masterErrorList);
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(masterErrorList)) {
|
||||||
|
validationResponseTO.setValid(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return validationResponseTO;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param validateCredentialRequestTO
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private List<ErrorData> validateUsername(ValidateCredentialRequestTO validateCredentialRequestTO) {
|
||||||
|
|
||||||
|
RuleResult ruleResult = applyRulesAndValidateUsername(validateCredentialRequestTO);
|
||||||
|
return retrieveUsernameValidationErrorData(ruleResult);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param validateCredentialRequestTO
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private List<ErrorData> validatePassword(ValidateCredentialRequestTO validateCredentialRequestTO) {
|
||||||
|
|
||||||
|
RuleResult ruleResult = applyRulesAndValidatePassword(validateCredentialRequestTO);
|
||||||
|
List<ErrorData> errorData = new ArrayList<ErrorData>();
|
||||||
|
|
||||||
|
errorData.addAll(retrievePasswordValidationErrorData(ruleResult));
|
||||||
|
|
||||||
|
if (0 == validateCredentialRequestTO.getUsername().length) {
|
||||||
|
errorData.add(usernameRequiredError());
|
||||||
|
}
|
||||||
|
|
||||||
|
return errorData;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param validateCredentialRequestTO
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private RuleResult applyRulesAndValidateUsername(ValidateCredentialRequestTO validateCredentialRequestTO) {
|
||||||
|
|
||||||
|
PasswordData usernameData = new PasswordData(new String(validateCredentialRequestTO.getUsername()));
|
||||||
|
|
||||||
|
List<Rule> validationRules = new ArrayList<Rule>();
|
||||||
|
|
||||||
|
validationRules.add(usernameEmailSubstringConstraint);
|
||||||
|
validationRules.add(usernameEnglishAllowedCharacterConstraint);
|
||||||
|
validationRules.add(usernameLengthConstraint);
|
||||||
|
validationRules.add(usernameLeadingTrailingSpaceConstraint);
|
||||||
|
|
||||||
|
PasswordValidator usernameValidator = new PasswordValidator(validationRules);
|
||||||
|
|
||||||
|
return usernameValidator.validate(usernameData);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param validateCredentialRequestTO
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private RuleResult applyRulesAndValidatePassword(ValidateCredentialRequestTO validateCredentialRequestTO) {
|
||||||
|
|
||||||
|
PasswordData passwordData = new PasswordData(new String(validateCredentialRequestTO.getPassword()));
|
||||||
|
passwordData.setUsername(new String(validateCredentialRequestTO.getUsername()));
|
||||||
|
|
||||||
|
List<Rule> validationRules = new ArrayList<Rule>();
|
||||||
|
|
||||||
|
validationRules.add(passwordEmailSubstringConstraint);
|
||||||
|
validationRules.add(passwordEnglishAllowedCharacterConstraint);
|
||||||
|
validationRules.add(passwordLengthConstraint);
|
||||||
|
validationRules.add(passwordSpecialCharacterConstraint);
|
||||||
|
validationRules.add(passwordUsernameConstraint);
|
||||||
|
|
||||||
|
PasswordValidator passwordValidator = new PasswordValidator(validationRules);
|
||||||
|
|
||||||
|
return passwordValidator.validate(passwordData);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private ErrorData usernameRequiredError() {
|
||||||
|
|
||||||
|
return ErrorData.builder().setId(FriendlyId.createFriendlyId()).setTitle("Missing required value.")
|
||||||
|
.setDetail("Username is required to check validity of password.")
|
||||||
|
.setSourcePointer(CredentialsResource.SOURCE_POINTER_USERNAME).setStatus("422").setCode("1213").build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ruleResult
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private List<ErrorData> retrieveUsernameValidationErrorData(RuleResult ruleResult) {
|
||||||
|
|
||||||
|
List<ErrorData> errors = new ArrayList<ErrorData>();
|
||||||
|
|
||||||
|
List<RuleResultDetail> ruleResultDetails = ruleResult.getDetails();
|
||||||
|
|
||||||
|
for (RuleResultDetail ruleResultDetail : ruleResultDetails) {
|
||||||
|
|
||||||
|
if (UsernameLengthConstraint.ERROR_CODE_MIN.equals(ruleResultDetail.getErrorCode())
|
||||||
|
|| UsernameLengthConstraint.ERROR_CODE_MAX.equals(ruleResultDetail.getErrorCode())) {
|
||||||
|
errors.add(usernameLengthConstraint.getErrorData());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UsernameEnglishAllowedCharacterConstraint.ERROR_CODE.equals(ruleResultDetail.getErrorCode())) {
|
||||||
|
errors.add(usernameEnglishAllowedCharacterConstraint.getErrorData());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UsernameEmailSubstringConstraint.ERROR_CODE.equals(ruleResultDetail.getErrorCode())
|
||||||
|
&& emailAddressSubstringRegex.equals(ruleResultDetail.getParameters().get("pattern").toString())) {
|
||||||
|
errors.add(usernameEmailSubstringConstraint.getErrorData());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UsernameLeadingTrailingSpaceConstraint.ERROR_CODE.equals(ruleResultDetail.getErrorCode())
|
||||||
|
&& leadingTrailingSpacesRegex.equals(ruleResultDetail.getParameters().get("pattern").toString())) {
|
||||||
|
errors.add(usernameLeadingTrailingSpaceConstraint.getErrorData());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ruleResult
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private List<ErrorData> retrievePasswordValidationErrorData(RuleResult ruleResult) {
|
||||||
|
|
||||||
|
List<ErrorData> errors = new ArrayList<ErrorData>();
|
||||||
|
|
||||||
|
List<RuleResultDetail> ruleResultDetails = ruleResult.getDetails();
|
||||||
|
|
||||||
|
for (RuleResultDetail ruleResultDetail : ruleResultDetails) {
|
||||||
|
|
||||||
|
if (PasswordLengthConstraint.ERROR_CODE_MIN.equals(ruleResultDetail.getErrorCode())
|
||||||
|
|| PasswordLengthConstraint.ERROR_CODE_MAX.equals(ruleResultDetail.getErrorCode())) {
|
||||||
|
errors.add(passwordLengthConstraint.getErrorData());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PasswordEnglishAllowedCharacterConstraint.ERROR_CODE.equals(ruleResultDetail.getErrorCode())) {
|
||||||
|
errors.add(passwordEnglishAllowedCharacterConstraint.getErrorData());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PasswordEmailSubstringConstraint.ERROR_CODE.equals(ruleResultDetail.getErrorCode())
|
||||||
|
&& emailAddressSubstringRegex.equals(ruleResultDetail.getParameters().get("pattern").toString())) {
|
||||||
|
errors.add(passwordEmailSubstringConstraint.getErrorData());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PasswordSpecialCharacterConstraint.ERROR_CODE.equals(ruleResultDetail.getErrorCode())) {
|
||||||
|
errors.add(passwordSpecialCharacterConstraint.getErrorData());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PasswordUsernameConstraint.ERROR_CODE.equals(ruleResultDetail.getErrorCode())) {
|
||||||
|
errors.add(passwordUsernameConstraint.getErrorData());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.service.to;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Data required for performing validation on the username and password.
|
||||||
|
*/
|
||||||
|
public class ValidateCredentialRequestTO {
|
||||||
|
|
||||||
|
private char[] username = new char[0];
|
||||||
|
|
||||||
|
private char[] password = new char[0];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public char[] getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param username
|
||||||
|
*/
|
||||||
|
public void setUsername(char[] username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char[] getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(char[] password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.service.to;
|
||||||
|
|
||||||
|
import io.crnk.core.engine.document.ErrorData;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Response for validating the username and password.
|
||||||
|
*/
|
||||||
|
public class ValidateCredentialResponseTO extends ValidationResponseTO {
|
||||||
|
|
||||||
|
// List of actual CRNK ErrorData objects.
|
||||||
|
List<ErrorData> errorData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<ErrorData> getErrorData() {
|
||||||
|
return errorData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param errorData
|
||||||
|
*/
|
||||||
|
public void setErrorData(List<ErrorData> errorData) {
|
||||||
|
this.errorData = errorData;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021-2022 John Groller
|
||||||
|
*/
|
||||||
|
package com.jkgroller.validationauthority.service.to;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Auhor john@grollerfamily.com
|
||||||
|
* <p>
|
||||||
|
* Common response for validations.
|
||||||
|
*/
|
||||||
|
public class ValidationResponseTO {
|
||||||
|
|
||||||
|
private boolean valid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isValid() {
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param valid
|
||||||
|
*/
|
||||||
|
public void setValid(boolean valid) {
|
||||||
|
this.valid = valid;
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/main/resources/application.yml
Normal file
18
src/main/resources/application.yml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
crnk:
|
||||||
|
path-prefix: /v1
|
||||||
|
return404-on-null: true
|
||||||
|
|
||||||
|
regex:
|
||||||
|
emailAddressSubstring: '[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}'
|
||||||
|
leadingTrailingSpaces: '^[ \t]+|[ \t]+$'
|
||||||
|
|
||||||
|
password:
|
||||||
|
validation:
|
||||||
|
minimumLength: 12
|
||||||
|
maximumLength: 256
|
||||||
|
numberOfSpecialCharacters: 1
|
||||||
|
|
||||||
|
username:
|
||||||
|
validation:
|
||||||
|
minimumLength: 5
|
||||||
|
maximumLength: 64
|
||||||
89
src/main/resources/errorCodesToChooseFrom.txt
Normal file
89
src/main/resources/errorCodesToChooseFrom.txt
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
6664
|
||||||
|
0217
|
||||||
|
5339
|
||||||
|
2055
|
||||||
|
6387
|
||||||
|
4255
|
||||||
|
5451
|
||||||
|
8133
|
||||||
|
3275
|
||||||
|
2462
|
||||||
|
1003
|
||||||
|
6263
|
||||||
|
3493
|
||||||
|
8646
|
||||||
|
7229
|
||||||
|
2352
|
||||||
|
3705
|
||||||
|
3729
|
||||||
|
5965
|
||||||
|
3486
|
||||||
|
5014
|
||||||
|
5456
|
||||||
|
9135
|
||||||
|
9880
|
||||||
|
4294
|
||||||
|
4252
|
||||||
|
5037
|
||||||
|
1754
|
||||||
|
9963
|
||||||
|
3317
|
||||||
|
3106
|
||||||
|
3955
|
||||||
|
6935
|
||||||
|
0231
|
||||||
|
0495
|
||||||
|
9995
|
||||||
|
7180
|
||||||
|
1578
|
||||||
|
2308
|
||||||
|
6281
|
||||||
|
8023
|
||||||
|
7540
|
||||||
|
6971
|
||||||
|
2577
|
||||||
|
1699
|
||||||
|
7036
|
||||||
|
0016
|
||||||
|
0907
|
||||||
|
0825
|
||||||
|
0405
|
||||||
|
1160
|
||||||
|
3837
|
||||||
|
1258
|
||||||
|
7419
|
||||||
|
4697
|
||||||
|
8219
|
||||||
|
8512
|
||||||
|
4962
|
||||||
|
5680
|
||||||
|
8187
|
||||||
|
4462
|
||||||
|
6483
|
||||||
|
3707
|
||||||
|
1381
|
||||||
|
7737
|
||||||
|
6606
|
||||||
|
1585
|
||||||
|
3752
|
||||||
|
8911
|
||||||
|
0542
|
||||||
|
0221
|
||||||
|
8833
|
||||||
|
3600
|
||||||
|
6968
|
||||||
|
7222
|
||||||
|
6436
|
||||||
|
1314
|
||||||
|
7990
|
||||||
|
0512
|
||||||
|
2864
|
||||||
|
1382
|
||||||
|
2495
|
||||||
|
6345
|
||||||
|
0492
|
||||||
|
7081
|
||||||
|
9321
|
||||||
|
9198
|
||||||
|
3796
|
||||||
|
3395
|
||||||
1
src/main/resources/licenseTemplate.txt
Normal file
1
src/main/resources/licenseTemplate.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
Copyright 2021-2022 John Groller
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"info": {
|
||||||
|
"_postman_id": "51726096-b531-47a9-bfed-39cca353f9e7",
|
||||||
|
"name": "ValidationAuthority",
|
||||||
|
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||||
|
},
|
||||||
|
"item": [
|
||||||
|
{
|
||||||
|
"name": "Create Credentials",
|
||||||
|
"request": {
|
||||||
|
"method": "POST",
|
||||||
|
"header": [
|
||||||
|
{
|
||||||
|
"key": "Content-Type",
|
||||||
|
"type": "text",
|
||||||
|
"value": "application/vnd.api+json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "Crnk-Compact",
|
||||||
|
"type": "text",
|
||||||
|
"value": "true",
|
||||||
|
"disabled": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"body": {
|
||||||
|
"mode": "raw",
|
||||||
|
"raw": "{\r\n \"data\": {\r\n \"type\": \"credentials\",\r\n \"attributes\": {\r\n \"username\": \"myUsername\",\r\n \"password\": \"ThePas$word1234\"\r\n }\r\n }\r\n}"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"raw": "http://localhost:8080/v1/credentials",
|
||||||
|
"protocol": "http",
|
||||||
|
"host": [
|
||||||
|
"localhost"
|
||||||
|
],
|
||||||
|
"port": "8080",
|
||||||
|
"path": [
|
||||||
|
"v1",
|
||||||
|
"credentials"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"event": [
|
||||||
|
{
|
||||||
|
"listen": "prerequest",
|
||||||
|
"script": {
|
||||||
|
"id": "384fd387-7f33-41fe-a425-31b02810bf3b",
|
||||||
|
"type": "text/javascript",
|
||||||
|
"exec": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"listen": "test",
|
||||||
|
"script": {
|
||||||
|
"id": "95eb4ff6-cea3-4ba8-9fcc-287be3ee781f",
|
||||||
|
"type": "text/javascript",
|
||||||
|
"exec": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"protocolProfileBehavior": {}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user