entry : result.getParameters().entrySet()) {
50 | exchange.addQueryParam(entry.getKey(), entry.getValue());
51 |
52 | exchange.addPathParam(entry.getKey(), entry.getValue());
53 | }
54 | }
55 |
56 | Handler.next(exchange, next);
57 | }
58 |
59 | @Override
60 | public HttpHandler getNext() {
61 | return next;
62 | }
63 |
64 | @Override
65 | public MiddlewareHandler setNext(HttpHandler next) {
66 | Handlers.handlerNotNull(next);
67 | this.next = next;
68 | return this;
69 | }
70 |
71 | @Override
72 | public boolean isEnabled() {
73 | return true;
74 | }
75 |
76 | @Override
77 | public void register() {
78 |
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/openapi-meta/src/test/java/com/networknt/openapi/parameter/QueryParameterDeserializerTest.java:
--------------------------------------------------------------------------------
1 | package com.networknt.openapi.parameter;
2 |
3 | import org.junit.Test;
4 |
5 | import com.networknt.oas.model.Parameter;
6 | import com.networknt.oas.model.Schema;
7 | import com.networknt.openapi.OpenApiHandler;
8 |
9 | import io.undertow.server.HttpServerExchange;
10 |
11 | public class QueryParameterDeserializerTest extends ParameterDeserializerTest{
12 | @Test
13 | public void test_form_array() {
14 | Schema schema = new PojoSchema();
15 | schema.setType(ValueType.ARRAY.name().toLowerCase());
16 |
17 | Parameter parameter = new PoJoParameter(PARAM_NAME,
18 | ParameterType.QUERY.name().toLowerCase(),
19 | QueryParameterStyle.FORM.name().toLowerCase(),
20 | false,
21 | schema);
22 |
23 | HttpServerExchange exchange = new HttpServerExchange(null);
24 |
25 | exchange.addQueryParam(PARAM_NAME, "3,4,5");
26 |
27 | checkArray(exchange, parameter);
28 | }
29 |
30 | @Test
31 | public void test_form_object_exploade() {
32 | Schema schema = new PojoSchema();
33 | schema.setType(ValueType.OBJECT.name().toLowerCase());
34 | schema.setProperties(PROPS);
35 |
36 | Parameter parameter = new PoJoParameter(PARAM_NAME,
37 | ParameterType.QUERY.name().toLowerCase(),
38 | QueryParameterStyle.FORM.name().toLowerCase(),
39 | true,
40 | schema);
41 |
42 | HttpServerExchange exchange = new HttpServerExchange(null);
43 |
44 | exchange.addQueryParam(ROLE, "admin");
45 | exchange.addQueryParam(FIRST_NAME, "Alex");
46 |
47 | checkMap(exchange, parameter, 3);
48 | }
49 |
50 | @Test
51 | public void test_form_object_no_exploade() {
52 | Schema schema = new PojoSchema();
53 | schema.setType(ValueType.OBJECT.name().toLowerCase());
54 | schema.setProperties(PROPS);
55 |
56 | Parameter parameter = new PoJoParameter(PARAM_NAME,
57 | ParameterType.QUERY.name().toLowerCase(),
58 | QueryParameterStyle.FORM.name().toLowerCase(),
59 | false,
60 | schema);
61 |
62 | HttpServerExchange exchange = new HttpServerExchange(null);
63 |
64 | exchange.addQueryParam(PARAM_NAME, "role,admin,firstName,Alex");
65 |
66 | checkMap(exchange, parameter, 2);
67 | }
68 |
69 | @Test
70 | public void test_spacedelimited_array() {
71 | Schema schema = new PojoSchema();
72 | schema.setType(ValueType.ARRAY.name().toLowerCase());
73 |
74 | Parameter parameter = new PoJoParameter(PARAM_NAME,
75 | ParameterType.QUERY.name().toLowerCase(),
76 | QueryParameterStyle.SPACEDELIMITED.name().toLowerCase(),
77 | false,
78 | schema);
79 |
80 | HttpServerExchange exchange = new HttpServerExchange(null);
81 |
82 | exchange.addQueryParam(PARAM_NAME, "3 4 5");
83 |
84 | checkArray(exchange, parameter);
85 | }
86 |
87 | @Test
88 | public void test_pipedelimited_array() {
89 | Schema schema = new PojoSchema();
90 | schema.setType(ValueType.ARRAY.name().toLowerCase());
91 |
92 | Parameter parameter = new PoJoParameter(PARAM_NAME,
93 | ParameterType.QUERY.name().toLowerCase(),
94 | QueryParameterStyle.PIPEDELIMITED.name().toLowerCase(),
95 | false,
96 | schema);
97 |
98 | HttpServerExchange exchange = new HttpServerExchange(null);
99 |
100 | exchange.addQueryParam(PARAM_NAME, "3|4|5");
101 |
102 | checkArray(exchange, parameter);
103 | }
104 |
105 | @Test
106 | public void test_deepobject() {
107 | Schema schema = new PojoSchema();
108 | schema.setType(ValueType.OBJECT.name().toLowerCase());
109 | schema.setProperties(PROPS);
110 |
111 | Parameter parameter = new PoJoParameter(PARAM_NAME,
112 | ParameterType.QUERY.name().toLowerCase(),
113 | QueryParameterStyle.DEEPOBJECT.name().toLowerCase(),
114 | true,
115 | schema);
116 |
117 | HttpServerExchange exchange = new HttpServerExchange(null);
118 |
119 | exchange.addQueryParam(String.format("%s[%s]", PARAM_NAME, ROLE), ADMIN);
120 | exchange.addQueryParam(String.format("%s[%s]", PARAM_NAME, FIRST_NAME), ALEX);
121 |
122 | checkMap(exchange, parameter, 3);
123 | }
124 |
125 | protected void checkArray(HttpServerExchange exchange, Parameter parameter) {
126 | ParameterType.QUERY.getDeserializer().deserialize(exchange, parameter, ParameterDeserializer.getCandidateQueryParams(exchange));
127 |
128 | checkArray(exchange.getAttachment(OpenApiHandler.DESERIALIZED_QUERY_PARAMETERS));
129 | }
130 |
131 | protected void checkMap(HttpServerExchange exchange, Parameter parameter, int expectedSize) {
132 | ParameterType.QUERY.getDeserializer().deserialize(exchange, parameter, ParameterDeserializer.getCandidateQueryParams(exchange));
133 | checkMap(exchange.getAttachment(OpenApiHandler.DESERIALIZED_QUERY_PARAMETERS), expectedSize);
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/openapi-meta/src/test/resources/config/client.truststore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/networknt/light-rest-4j/27c19bbaf3ad3792007aa89dc6b8f018c52178c0/openapi-meta/src/test/resources/config/client.truststore
--------------------------------------------------------------------------------
/openapi-meta/src/test/resources/config/handler.yml:
--------------------------------------------------------------------------------
1 | ---
2 | enabled: true
3 |
4 | # Configuration for the LightHttpHandler. The handler is the base class for all middleware, server and health handlers
5 | # set the Status Object in the AUDIT_INFO, for auditing purposes
6 | # default, if not set:false
7 | auditOnError: true
8 |
9 | # set the StackTrace in the AUDIT_INFO, for auditing purposes
10 | # default, if not set:false
11 | auditStackTrace: true
12 |
13 | handlers:
14 | - com.networknt.handler.sample.SampleHttpHandler1
15 | - com.networknt.handler.sample.SampleHttpHandler2
16 | - com.networknt.handler.sample.SampleHttpHandler3@third
17 |
18 | chains:
19 | secondBeforeFirst:
20 | - com.networknt.handler.sample.SampleHttpHandler2
21 | - com.networknt.handler.sample.SampleHttpHandler1
22 |
23 | paths:
24 | - path: '/test'
25 | method: 'get'
26 | exec:
27 | - secondBeforeFirst
28 | - third
29 | - path: '/v2/health'
30 | method: 'post'
31 | exec:
32 | - secondBeforeFirst
33 | - third
34 | # If there is no matched path, then it goes here first. If this is not set, then an error
35 | # will be returned.
36 | defaultHandlers:
37 | - third
38 |
--------------------------------------------------------------------------------
/openapi-meta/src/test/resources/config/openapi-handler-multiple.yml:
--------------------------------------------------------------------------------
1 | # openapi-handler.yml
2 | # This configuration file is used to support multiple OpenAPI specifications in the same light-rest-4j instance.
3 | # An indicator to allow multiple openapi specifications. Default to false which only allow one spec named openapi.yml or openapi.yaml or openapi.json.
4 | multipleSpec: ${openapi-handler.multipleSpec:true}
5 | # When the OpenApiHandler is used in a shared gateway and some backend APIs have no specifications deployed on the gateway, the handler will return
6 | # an invalid request path error to the client. To allow the call to pass through the OpenApiHandler and route to the backend APIs, you can set this
7 | # flag to true. In this mode, the handler will only add the endpoint specification to the auditInfo if it can find it. Otherwise, it will pass through.
8 | ignoreInvalidPath: ${openapi-handler.ignoreInvalidPath:false}
9 | # Path to spec mapping. One or more base paths can map to the same specifications. The key is the base path and the value is the specification name.
10 | # If users want to use multiple specification files in the same instance, each specification must have a unique base path and it must be set as key.
11 | pathSpecMapping:
12 | /petstore: openapi-petstore
13 | /market: openapi-market
14 |
--------------------------------------------------------------------------------
/openapi-meta/src/test/resources/config/openapi-inject-test-dup-method.yml:
--------------------------------------------------------------------------------
1 | openapi: 3.0.0
2 | paths:
3 | /pets/{petId}:
4 | get:
5 | security:
6 | - api-scope:
7 | - admim
8 |
9 | components:
10 | securitySchemes:
11 | api-scope:
12 | flows:
13 | clientCredentials:
14 | scopes:
15 | admin: orwritten
16 |
--------------------------------------------------------------------------------
/openapi-meta/src/test/resources/config/openapi-inject-test-dup-path.yml:
--------------------------------------------------------------------------------
1 | openapi: 3.0.0
2 | paths:
3 | /pets/{petId}:
4 | # the original spec does not contain put method
5 | put:
6 | security:
7 | - api-scope:
8 | - admim
9 |
10 | components:
11 | securitySchemes:
12 | api-scope:
13 | flows:
14 | clientCredentials:
15 | scopes:
16 | admin: orwritten
17 |
--------------------------------------------------------------------------------
/openapi-meta/src/test/resources/config/openapi-inject-test-neg.yml:
--------------------------------------------------------------------------------
1 | openapi: 3.0.0
2 | paths:
3 | /pets/${badKey}:
4 | get:
5 | security:
6 | - api-scope:
7 | - admim
8 |
9 | components:
10 | securitySchemes:
11 | api-scope:
12 | flows:
13 | clientCredentials:
14 | scopes:
15 | admin: orwritten
16 |
--------------------------------------------------------------------------------
/openapi-meta/src/test/resources/config/openapi-inject-test-pos.yml:
--------------------------------------------------------------------------------
1 | openapi: 3.0.0
2 | paths:
3 | /pets/${goodKey}:
4 | get:
5 | security:
6 | - api-scope:
7 | - admim
8 |
9 | components:
10 | securitySchemes:
11 | api-scope:
12 | flows:
13 | clientCredentials:
14 | scopes:
15 | admin: orwritten
16 |
--------------------------------------------------------------------------------
/openapi-meta/src/test/resources/config/openapi-market.yaml:
--------------------------------------------------------------------------------
1 | openapi: 3.0.0
2 | info:
3 | version: 1.0.0
4 | title: Swagger Market
5 | license:
6 | name: MIT
7 | servers:
8 | - url: 'http://market.swagger.io/market'
9 | paths:
10 | /{store}/products:
11 | get:
12 | summary: Get all products from stores
13 | operationId: listProducts
14 | tags:
15 | - products
16 | parameters:
17 | - name: limit
18 | in: query
19 | description: How many items to return at one time (max 100)
20 | required: false
21 | schema:
22 | type: integer
23 | format: int32
24 | - name: store
25 | in: path
26 | description: The downstream store name
27 | required: true
28 | schema:
29 | type: string
30 | security:
31 | - market_auth:
32 | - 'read:products'
33 | responses:
34 | '200':
35 | description: An paged array of products
36 | content:
37 | application/json:
38 | schema:
39 | type: array
40 | items:
41 | $ref: '#/components/schemas/Product'
42 | example:
43 | - id: 1
44 | name: catten
45 | tag: cat
46 | - id: 2
47 | name: doggy
48 | tag: dog
49 | default:
50 | description: unexpected error
51 | content:
52 | application/json:
53 | schema:
54 | $ref: '#/components/schemas/Error'
55 | post:
56 | summary: Create a product
57 | operationId: createProducts
58 | parameters:
59 | - name: store
60 | in: path
61 | description: The downstream store name
62 | required: true
63 | schema:
64 | type: string
65 | requestBody:
66 | description: Product to add to the target store
67 | required: true
68 | content:
69 | application/json:
70 | schema:
71 | $ref: '#/components/schemas/Product'
72 | tags:
73 | - products
74 | security:
75 | - market_auth:
76 | - 'read:products'
77 | - 'write:products'
78 | responses:
79 | '201':
80 | description: Null response
81 | default:
82 | description: unexpected error
83 | content:
84 | application/json:
85 | schema:
86 | $ref: '#/components/schemas/Error'
87 | components:
88 | securitySchemes:
89 | market_auth:
90 | type: oauth2
91 | description: This API uses OAuth 2 with the client credential grant flow.
92 | flows:
93 | clientCredentials:
94 | tokenUrl: 'https://localhost:6882/token'
95 | scopes:
96 | 'write:products': modify products
97 | 'read:products': read your products
98 | schemas:
99 | Product:
100 | type: object
101 | required:
102 | - id
103 | - name
104 | properties:
105 | id:
106 | type: integer
107 | format: int64
108 | name:
109 | type: string
110 | tag:
111 | type: string
112 | Error:
113 | type: object
114 | required:
115 | - code
116 | - message
117 | properties:
118 | code:
119 | type: integer
120 | format: int32
121 | message:
122 | type: string
123 |
--------------------------------------------------------------------------------
/openapi-meta/src/test/resources/config/openapi-petstore.yaml:
--------------------------------------------------------------------------------
1 | openapi: 3.0.0
2 | info:
3 | version: 1.0.0
4 | title: Swagger Petstore
5 | license:
6 | name: MIT
7 | servers:
8 | - url: 'http://petstore.swagger.io/petstore'
9 | paths:
10 | /pets:
11 | get:
12 | summary: List all pets
13 | operationId: listPets
14 | tags:
15 | - pets
16 | parameters:
17 | - name: limit
18 | in: query
19 | description: How many items to return at one time (max 100)
20 | required: false
21 | schema:
22 | type: integer
23 | format: int32
24 | security:
25 | - petstore_auth:
26 | - 'read:pets'
27 | responses:
28 | '200':
29 | description: An paged array of pets
30 | headers:
31 | x-next:
32 | description: A link to the next page of responses
33 | schema:
34 | type: string
35 | content:
36 | application/json:
37 | schema:
38 | type: array
39 | items:
40 | $ref: '#/components/schemas/Pet'
41 | example:
42 | - id: 1
43 | name: catten
44 | tag: cat
45 | - id: 2
46 | name: doggy
47 | tag: dog
48 | default:
49 | description: unexpected error
50 | content:
51 | application/json:
52 | schema:
53 | $ref: '#/components/schemas/Error'
54 | post:
55 | summary: Create a pet
56 | operationId: createPets
57 | requestBody:
58 | description: Pet to add to the store
59 | required: true
60 | content:
61 | application/json:
62 | schema:
63 | $ref: '#/components/schemas/Pet'
64 | tags:
65 | - pets
66 | security:
67 | - petstore_auth:
68 | - 'read:pets'
69 | - 'write:pets'
70 | responses:
71 | '201':
72 | description: Null response
73 | default:
74 | description: unexpected error
75 | content:
76 | application/json:
77 | schema:
78 | $ref: '#/components/schemas/Error'
79 | '/pets/{petId}':
80 | get:
81 | summary: Info for a specific pet
82 | operationId: showPetById
83 | tags:
84 | - pets
85 | parameters:
86 | - name: petId
87 | in: path
88 | required: true
89 | description: The id of the pet to retrieve
90 | schema:
91 | type: string
92 | security:
93 | - petstore_auth:
94 | - 'read:pets'
95 | responses:
96 | '200':
97 | description: Expected response to a valid request
98 | content:
99 | application/json:
100 | schema:
101 | $ref: '#/components/schemas/Pet'
102 | example:
103 | id: 1
104 | name: Jessica Right
105 | tag: pet
106 | default:
107 | description: unexpected error
108 | content:
109 | application/json:
110 | schema:
111 | $ref: '#/components/schemas/Error'
112 | delete:
113 | summary: Delete a specific pet
114 | operationId: deletePetById
115 | tags:
116 | - pets
117 | parameters:
118 | - name: petId
119 | in: path
120 | required: true
121 | description: The id of the pet to delete
122 | schema:
123 | type: string
124 | - name: key
125 | in: header
126 | required: true
127 | description: The key header
128 | schema:
129 | type: string
130 | security:
131 | - petstore_auth:
132 | - 'write:pets'
133 | responses:
134 | '200':
135 | description: Expected response to a valid request
136 | content:
137 | application/json:
138 | schema:
139 | $ref: '#/components/schemas/Pet'
140 | examples:
141 | response:
142 | value:
143 | id: 1
144 | name: Jessica Right
145 | tag: pet
146 | default:
147 | description: unexpected error
148 | content:
149 | application/json:
150 | schema:
151 | $ref: '#/components/schemas/Error'
152 | /notifications:
153 | get:
154 | summary: Get Notifications
155 | operationId: listNotifications
156 | tags:
157 | - notifications
158 | security:
159 | - petstore_auth:
160 | - 'read:pets'
161 | responses:
162 | '200':
163 | description: A standard notification response in JSON for response interceptor test
164 |
165 | /flowers:
166 | post:
167 | summary: The API accept XML and the consumer is using JSON
168 | operationId: flowers
169 | tags:
170 | - flowers
171 | security:
172 | - petstore_auth:
173 | - 'read:pets'
174 | responses:
175 | '200':
176 | description: Return an flowers XML as the demo soap service
177 |
178 | components:
179 | securitySchemes:
180 | petstore_auth:
181 | type: oauth2
182 | description: This API uses OAuth 2 with the client credential grant flow.
183 | flows:
184 | clientCredentials:
185 | tokenUrl: 'https://localhost:6882/token'
186 | scopes:
187 | 'write:pets': modify pets in your account
188 | 'read:pets': read your pets
189 | schemas:
190 | Pet:
191 | type: object
192 | required:
193 | - id
194 | - name
195 | properties:
196 | id:
197 | type: integer
198 | format: int64
199 | name:
200 | type: string
201 | tag:
202 | type: string
203 | Error:
204 | type: object
205 | required:
206 | - code
207 | - message
208 | properties:
209 | code:
210 | type: integer
211 | format: int32
212 | message:
213 | type: string
214 |
--------------------------------------------------------------------------------
/openapi-meta/src/test/resources/config/values.yml:
--------------------------------------------------------------------------------
1 | # server.yml
2 | server.serviceId: com.networknt.petstore-1.0.0
3 | badKey: "{petId}"
4 | goodKey: petId
5 |
--------------------------------------------------------------------------------
/openapi-meta/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | TODO create logger for audit only.
20 | http://stackoverflow.com/questions/2488558/logback-to-log-different-messages-to-two-files
21 |
22 | PROFILER
23 |
24 | NEUTRAL
25 |
26 |
27 |
28 |
30 |
31 | %d{HH:mm:ss.SSS} [%thread] %-5marker %-5level %logger{36} - %msg%n
32 |
33 |
34 |
35 |
36 | target/test.log
37 | false
38 |
39 | %d{HH:mm:ss.SSS} [%thread] %-5level %class{36}:%L %M - %msg%n
40 |
41 |
42 |
43 |
44 |
45 | target/audit.log
46 |
47 | %-5level [%thread] %date{ISO8601} %F:%L - %msg%n
48 | true
49 |
50 |
51 | target/audit.log.%i.zip
52 | 1
53 | 5
54 |
55 |
56 | 200MB
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/openapi-security/pom.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
19 | 4.0.0
20 |
21 |
22 | com.networknt
23 | light-rest-4j
24 | 2.2.3-SNAPSHOT
25 | ../pom.xml
26 |
27 |
28 | openapi-security
29 | jar
30 | openapi-security
31 | An OpenAPI Specification 3.0 security module that contains all handlers to protect your server
32 |
33 |
34 |
35 | com.networknt
36 | http-string
37 |
38 |
39 | com.networknt
40 | config
41 |
42 |
43 | com.networknt
44 | client
45 |
46 |
47 | com.networknt
48 | utility
49 |
50 |
51 | com.networknt
52 | security
53 |
54 |
55 | com.networknt
56 | unified-config
57 |
58 |
59 | com.networknt
60 | unified-security
61 | ${version.light-4j}
62 |
63 |
64 | com.networknt
65 | handler
66 |
67 |
68 | com.networknt
69 | status
70 |
71 |
72 | com.networknt
73 | basic-auth
74 |
75 |
76 | com.networknt
77 | api-key
78 |
79 |
80 | com.networknt
81 | server
82 |
83 |
84 | com.networknt
85 | json-overlay
86 |
87 |
88 | com.networknt
89 | openapi-parser
90 |
91 |
92 | com.networknt
93 | openapi-meta
94 |
95 |
96 | io.undertow
97 | undertow-core
98 |
99 |
100 | com.fasterxml.jackson.core
101 | jackson-databind
102 |
103 |
104 | org.slf4j
105 | slf4j-api
106 |
107 |
108 | org.owasp.encoder
109 | encoder
110 |
111 |
112 | org.bitbucket.b_c
113 | jose4j
114 |
115 |
116 |
117 | ch.qos.logback
118 | logback-classic
119 | test
120 |
121 |
122 | junit
123 | junit
124 | test
125 |
126 |
127 | org.apache.commons
128 | commons-text
129 | test
130 |
131 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/openapi-security/src/main/java/com/networknt/openapi/SimpleJwtVerifyHandler.java:
--------------------------------------------------------------------------------
1 | package com.networknt.openapi;
2 |
3 | import com.networknt.config.Config;
4 | import com.networknt.handler.Handler;
5 | import com.networknt.handler.MiddlewareHandler;
6 | import com.networknt.handler.config.HandlerConfig;
7 | import com.networknt.security.*;
8 | import com.networknt.utility.ModuleRegistry;
9 | import io.undertow.Handlers;
10 | import io.undertow.server.HttpHandler;
11 | import io.undertow.server.HttpServerExchange;
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 |
15 | /**
16 | * This is very simple jwt verify handler that is used to verify jwt token without scopes. Other than scopes, it is
17 | * the same as the normal JwtVerifyHandler.
18 | *
19 | * @author Steve Hu
20 | */
21 | public class SimpleJwtVerifyHandler extends AbstractSimpleJwtVerifyHandler {
22 | static final Logger logger = LoggerFactory.getLogger(SimpleJwtVerifyHandler.class);
23 |
24 | String basePath;
25 |
26 | public SimpleJwtVerifyHandler() {
27 | // at this moment, we assume that the OpenApiHandler is fully loaded with a single spec or multiple specs.
28 | // And the basePath is the correct one from the OpenApiHandler helper or helperMap if multiple is used.
29 | config = SecurityConfig.load();
30 | jwtVerifier = new JwtVerifier(config);
31 | // in case that the specification doesn't exist, get the basePath from the handler.yml for endpoint lookup.
32 | HandlerConfig handlerConfig = HandlerConfig.load();
33 | this.basePath = handlerConfig == null ? "/" : handlerConfig.getBasePath();
34 | }
35 |
36 | @Override
37 | public HttpHandler getNext() {
38 | return next;
39 | }
40 |
41 | @Override
42 | public MiddlewareHandler setNext(final HttpHandler next) {
43 | Handlers.handlerNotNull(next);
44 | this.next = next;
45 | return this;
46 | }
47 |
48 | @Override
49 | public boolean isEnabled() {
50 | return config.isEnableVerifyJwt();
51 | }
52 |
53 | @Override
54 | public void register() {
55 | ModuleRegistry.registerModule(SecurityConfig.CONFIG_NAME, SimpleJwtVerifyHandler.class.getName(), Config.getNoneDecryptedInstance().getJsonMapConfigNoCache(SecurityConfig.CONFIG_NAME), null);
56 | }
57 |
58 | @Override
59 | public void reload() {
60 | config.reload();
61 | jwtVerifier = new JwtVerifier(config);
62 | ModuleRegistry.registerModule(SecurityConfig.CONFIG_NAME, SimpleJwtVerifyHandler.class.getName(), Config.getNoneDecryptedInstance().getJsonMapConfigNoCache(SecurityConfig.CONFIG_NAME), null);
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/openapi-security/src/main/resources/config/primary.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE
3 | CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl
4 | Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw
5 | MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x
6 | FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg
7 | SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD
8 | ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf
9 | rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt
10 | SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm
11 | J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw
12 | 6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O
13 | BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF
14 | slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6
15 | 5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro
16 | K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4
17 | dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+
18 | BudoEVJlIlmS0aRCuP8n
19 | -----END CERTIFICATE-----
20 |
--------------------------------------------------------------------------------
/openapi-security/src/main/resources/config/secondary.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE
3 | CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v
4 | bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1
5 | OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G
6 | A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK
7 | BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
8 | AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U
9 | rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB
10 | 0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ
11 | UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg
12 | EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek
13 | spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5
14 | 1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7
15 | x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC
16 | 8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ
17 | NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW
18 | owVmdKg/0w==
19 | -----END CERTIFICATE-----
20 |
--------------------------------------------------------------------------------
/openapi-security/src/test/java/com/networknt/openapi/TestServer.java:
--------------------------------------------------------------------------------
1 | package com.networknt.openapi;
2 |
3 | import com.networknt.server.Server;
4 | import com.networknt.server.ServerConfig;
5 | import org.junit.rules.ExternalResource;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | import java.util.concurrent.atomic.AtomicInteger;
10 |
11 | public class TestServer extends ExternalResource {
12 | static final Logger logger = LoggerFactory.getLogger(TestServer.class);
13 |
14 | private static final AtomicInteger refCount = new AtomicInteger(0);
15 | private static Server server;
16 |
17 | private static final TestServer instance = new TestServer();
18 |
19 | public static TestServer getInstance () {
20 | return instance;
21 | }
22 |
23 | private TestServer() {
24 |
25 | }
26 |
27 | public ServerConfig getServerConfig() {
28 | return ServerConfig.getInstance();
29 | }
30 |
31 | @Override
32 | protected void before() {
33 | try {
34 | if (refCount.get() == 0) {
35 | Server.start();
36 | }
37 | }
38 | finally {
39 | refCount.getAndIncrement();
40 | }
41 | }
42 |
43 | @Override
44 | protected void after() {
45 | refCount.getAndDecrement();
46 | if (refCount.get() == 0) {
47 | Server.stop();
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/openapi-security/src/test/resources/config/client.truststore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/networknt/light-rest-4j/27c19bbaf3ad3792007aa89dc6b8f018c52178c0/openapi-security/src/test/resources/config/client.truststore
--------------------------------------------------------------------------------
/openapi-security/src/test/resources/config/handler.yml:
--------------------------------------------------------------------------------
1 | # Handler middleware chain configuration
2 | ---
3 | enabled: true
4 |
5 | # Configuration for the LightHttpHandler. The handler is the base class for all middleware, server and health handlers
6 | # set the Status Object in the AUDIT_INFO, for auditing purposes
7 | # default, if not set:false
8 | auditOnError: ${handler.auditOnError:false}
9 |
10 | # set the StackTrace in the AUDIT_INFO, for auditing purposes
11 | # default, if not set:false
12 | auditStackTrace: ${handler.auditStackTrace:false}
13 |
14 | # Base Path of the API endpoints
15 | basePath: ${handler.basePath:/}
16 |
17 | #------------------------------------------------------------------------------
18 | # Support individual handler chains for each separate endpoint. It allows framework
19 | # handlers like health check, server info to bypass majority of the middleware handlers
20 | # and allows mixing multiple frameworks like OpenAPI and GraphQL in the same instance.
21 | #
22 | # handlers -- list of handlers to be used across chains in this microservice
23 | # including the routing handlers for ALL endpoints
24 | # -- format: fully qualified handler class name@optional:given name
25 | # chains -- allows forming of [1..N] chains, which could be wholly or
26 | # used to form handler chains for each endpoint
27 | # ex.: default chain below, reused partially across multiple endpoints
28 | # paths -- list all the paths to be used for routing within the microservice
29 | # ---- path: the URI for the endpoint (ex.: path: '/v1/pets')
30 | # ---- method: the operation in use (ex.: 'post')
31 | # ---- exec: handlers to be executed -- this element forms the list and
32 | # the order of execution for the handlers
33 | #
34 | # IMPORTANT NOTES:
35 | # - to avoid executing a handler, it has to be removed/commented out in the chain
36 | # or change the enabled:boolean to false for a middleware handler configuration.
37 | # - all handlers, routing handler included, are to be listed in the execution chain
38 | # - for consistency, give a name to each handler; it is easier to refer to a name
39 | # vs a fully qualified class name and is more elegant
40 | # - you can list in chains the fully qualified handler class names, and avoid using the
41 | # handlers element altogether
42 | #------------------------------------------------------------------------------
43 | handlers: ${handler.handlers:}
44 |
45 | chains:
46 | default: ${handler.chains.default:}
47 |
48 | paths:
49 | - path: '/*'
50 | method: 'GET'
51 | exec:
52 | - default
53 | - path: '/*'
54 | method: 'POST'
55 | exec:
56 | - default
57 | - path: '/*'
58 | method: 'PUT'
59 | exec:
60 | - default
61 | - path: '/*'
62 | method: 'DELETE'
63 | exec:
64 | - default
65 | - path: '/*'
66 | method: 'PATCH'
67 | exec:
68 | - default
69 |
--------------------------------------------------------------------------------
/openapi-security/src/test/resources/config/openapi-handler-multiple.yml:
--------------------------------------------------------------------------------
1 | # openapi-handler.yml
2 | # This configuration file is used to support multiple OpenAPI specifications in the same light-rest-4j instance.
3 | # An indicator to allow multiple openapi specifications. Default to false which only allow one spec named openapi.yml or openapi.yaml or openapi.json.
4 | multipleSpec: ${openapi-handler.multipleSpec:true}
5 | # Path to spec mapping. One or more base paths can map to the same specifications. The key is the base path and the value is the specification name.
6 | # If users want to use multiple specification files in the same instance, each specification must have a unique base path and it must be set as key.
7 | pathSpecMapping:
8 | /petstore: openapi-petstore
9 | /market: openapi-market
10 |
--------------------------------------------------------------------------------
/openapi-security/src/test/resources/config/openapi-market.yaml:
--------------------------------------------------------------------------------
1 | openapi: 3.0.0
2 | info:
3 | version: 1.0.0
4 | title: Swagger Market
5 | license:
6 | name: MIT
7 | servers:
8 | - url: 'http://market.swagger.io/market'
9 | paths:
10 | /{store}/products:
11 | get:
12 | summary: Get all products from stores
13 | operationId: listProducts
14 | tags:
15 | - products
16 | parameters:
17 | - name: limit
18 | in: query
19 | description: How many items to return at one time (max 100)
20 | required: false
21 | schema:
22 | type: integer
23 | format: int32
24 | - name: store
25 | in: path
26 | description: The downstream store name
27 | required: true
28 | schema:
29 | type: string
30 | security:
31 | - market_auth:
32 | - 'read:products'
33 | responses:
34 | '200':
35 | description: An paged array of products
36 | content:
37 | application/json:
38 | schema:
39 | type: array
40 | items:
41 | $ref: '#/components/schemas/Product'
42 | example:
43 | - id: 1
44 | name: catten
45 | tag: cat
46 | - id: 2
47 | name: doggy
48 | tag: dog
49 | default:
50 | description: unexpected error
51 | content:
52 | application/json:
53 | schema:
54 | $ref: '#/components/schemas/Error'
55 | post:
56 | summary: Create a product
57 | operationId: createProducts
58 | parameters:
59 | - name: store
60 | in: path
61 | description: The downstream store name
62 | required: true
63 | schema:
64 | type: string
65 | requestBody:
66 | description: Product to add to the target store
67 | required: true
68 | content:
69 | application/json:
70 | schema:
71 | $ref: '#/components/schemas/Product'
72 | tags:
73 | - products
74 | security:
75 | - market_auth:
76 | - 'read:products'
77 | - 'write:products'
78 | responses:
79 | '201':
80 | description: Null response
81 | default:
82 | description: unexpected error
83 | content:
84 | application/json:
85 | schema:
86 | $ref: '#/components/schemas/Error'
87 | components:
88 | securitySchemes:
89 | market_auth:
90 | type: oauth2
91 | description: This API uses OAuth 2 with the client credential grant flow.
92 | flows:
93 | clientCredentials:
94 | tokenUrl: 'https://localhost:6882/token'
95 | scopes:
96 | 'write:products': modify products
97 | 'read:products': read your products
98 | schemas:
99 | Product:
100 | type: object
101 | required:
102 | - id
103 | - name
104 | properties:
105 | id:
106 | type: integer
107 | format: int64
108 | name:
109 | type: string
110 | tag:
111 | type: string
112 | Error:
113 | type: object
114 | required:
115 | - code
116 | - message
117 | properties:
118 | code:
119 | type: integer
120 | format: int32
121 | message:
122 | type: string
123 |
--------------------------------------------------------------------------------
/openapi-security/src/test/resources/config/openapi-petstore.yaml:
--------------------------------------------------------------------------------
1 | openapi: 3.0.0
2 | info:
3 | version: 1.0.0
4 | title: Swagger Petstore
5 | license:
6 | name: MIT
7 | servers:
8 | - url: 'http://petstore.swagger.io/petstore'
9 | paths:
10 | /pets:
11 | get:
12 | summary: List all pets
13 | operationId: listPets
14 | tags:
15 | - pets
16 | parameters:
17 | - name: limit
18 | in: query
19 | description: How many items to return at one time (max 100)
20 | required: false
21 | schema:
22 | type: integer
23 | format: int32
24 | security:
25 | - petstore_auth:
26 | - 'read:pets'
27 | responses:
28 | '200':
29 | description: An paged array of pets
30 | headers:
31 | x-next:
32 | description: A link to the next page of responses
33 | schema:
34 | type: string
35 | content:
36 | application/json:
37 | schema:
38 | type: array
39 | items:
40 | $ref: '#/components/schemas/Pet'
41 | example:
42 | - id: 1
43 | name: catten
44 | tag: cat
45 | - id: 2
46 | name: doggy
47 | tag: dog
48 | default:
49 | description: unexpected error
50 | content:
51 | application/json:
52 | schema:
53 | $ref: '#/components/schemas/Error'
54 | post:
55 | summary: Create a pet
56 | operationId: createPets
57 | requestBody:
58 | description: Pet to add to the store
59 | required: true
60 | content:
61 | application/json:
62 | schema:
63 | $ref: '#/components/schemas/Pet'
64 | tags:
65 | - pets
66 | security:
67 | - petstore_auth:
68 | - 'read:pets'
69 | - 'write:pets'
70 | responses:
71 | '201':
72 | description: Null response
73 | default:
74 | description: unexpected error
75 | content:
76 | application/json:
77 | schema:
78 | $ref: '#/components/schemas/Error'
79 | '/pets/{petId}':
80 | get:
81 | summary: Info for a specific pet
82 | operationId: showPetById
83 | tags:
84 | - pets
85 | parameters:
86 | - name: petId
87 | in: path
88 | required: true
89 | description: The id of the pet to retrieve
90 | schema:
91 | type: string
92 | security:
93 | - petstore_auth:
94 | - 'read:pets'
95 | responses:
96 | '200':
97 | description: Expected response to a valid request
98 | content:
99 | application/json:
100 | schema:
101 | $ref: '#/components/schemas/Pet'
102 | example:
103 | id: 1
104 | name: Jessica Right
105 | tag: pet
106 | default:
107 | description: unexpected error
108 | content:
109 | application/json:
110 | schema:
111 | $ref: '#/components/schemas/Error'
112 | delete:
113 | summary: Delete a specific pet
114 | operationId: deletePetById
115 | tags:
116 | - pets
117 | parameters:
118 | - name: petId
119 | in: path
120 | required: true
121 | description: The id of the pet to delete
122 | schema:
123 | type: string
124 | - name: key
125 | in: header
126 | required: true
127 | description: The key header
128 | schema:
129 | type: string
130 | security:
131 | - petstore_auth:
132 | - 'write:pets'
133 | responses:
134 | '200':
135 | description: Expected response to a valid request
136 | content:
137 | application/json:
138 | schema:
139 | $ref: '#/components/schemas/Pet'
140 | examples:
141 | response:
142 | value:
143 | id: 1
144 | name: Jessica Right
145 | tag: pet
146 | default:
147 | description: unexpected error
148 | content:
149 | application/json:
150 | schema:
151 | $ref: '#/components/schemas/Error'
152 | /notifications:
153 | get:
154 | summary: Get Notifications
155 | operationId: listNotifications
156 | tags:
157 | - notifications
158 | security:
159 | - petstore_auth:
160 | - 'read:pets'
161 | responses:
162 | '200':
163 | description: A standard notification response in JSON for response interceptor test
164 |
165 | /flowers:
166 | post:
167 | summary: The API accept XML and the consumer is using JSON
168 | operationId: flowers
169 | tags:
170 | - flowers
171 | security:
172 | - petstore_auth:
173 | - 'read:pets'
174 | responses:
175 | '200':
176 | description: Return an flowers XML as the demo soap service
177 |
178 | components:
179 | securitySchemes:
180 | petstore_auth:
181 | type: oauth2
182 | description: This API uses OAuth 2 with the client credential grant flow.
183 | flows:
184 | clientCredentials:
185 | tokenUrl: 'https://localhost:6882/token'
186 | scopes:
187 | 'write:pets': modify pets in your account
188 | 'read:pets': read your pets
189 | schemas:
190 | Pet:
191 | type: object
192 | required:
193 | - id
194 | - name
195 | properties:
196 | id:
197 | type: integer
198 | format: int64
199 | name:
200 | type: string
201 | tag:
202 | type: string
203 | Error:
204 | type: object
205 | required:
206 | - code
207 | - message
208 | properties:
209 | code:
210 | type: integer
211 | format: int32
212 | message:
213 | type: string
214 |
--------------------------------------------------------------------------------
/openapi-security/src/test/resources/config/unified-security.yml:
--------------------------------------------------------------------------------
1 | # unified-security.yml
2 | # indicate if this handler is enabled. By default, it will be enabled if it is injected into the
3 | # request/response chain in the handler.yml configuration.
4 | enabled: ${unified-security.enabled:true}
5 | # Anonymous prefixes configuration. A list of request path prefixes. The anonymous prefixes will be checked
6 | # first, and if any path is matched, all other security checks will be bypassed, and the request goes to
7 | # the next handler in the chain. You can use json array or string separated by comma or YAML format.
8 | anonymousPrefixes:
9 | - /v1/cats
10 | - /v1/dogs
11 | - /oauth2
12 |
13 | pathPrefixAuths:
14 | - prefix: /v1/salesforce
15 | basic: true
16 | jwt: true
17 | apikey: true
18 | jwkServiceIds: com.networknt.petstore-1.0.0, com.networknt.market-1.0.0
19 | - prefix: /v1/blackrock
20 | basic: true
21 | jwt: true
22 | jwkServiceIds: ["com.networknt.petstore-1.0.0", "com.networknt.market-1.0.0"]
23 | - prefix: /v1/test1
24 | apikey: true
25 | - prefix: /v1/pets
26 | jwt: true
27 |
--------------------------------------------------------------------------------
/openapi-security/src/test/resources/config/values.yml:
--------------------------------------------------------------------------------
1 | # server.yml
2 | server.enableHttps: false
3 | server.enableHttp2: false
4 | server.enableHttp: true
5 | server.httpPort: 7081
6 | server.ioThreads: 16
7 |
8 | # handler.yml
9 | handler.basePath: /
10 | handler.handlers:
11 | - com.networknt.openapi.OpenApiHandler@specification
12 | - com.networknt.openapi.JwtVerifyHandler@jwt
13 | - com.networknt.openapi.SimpleJwtVerifyHandler@sjwt
14 | - com.networknt.openapi.SwtVerifyHandler@swt
15 | - com.networknt.basicauth.BasicAuthHandler@basic
16 | - com.networknt.security.UnifiedSecurityHandler@unified
17 | - com.networknt.apikey.ApiKeyHandler@apikey
18 |
19 | handler.chains.default:
20 | - specification
21 | - unified
22 |
23 | # basic-auth.yml
24 | basic.enabled: true
25 | basic.users:
26 | - username: user1
27 | password: user1pass
28 | paths:
29 | - /v1/address
30 | - /v1/salesforce
31 | - username: user2
32 | password: CRYPT:0754fbc37347c136be7725cbf62b6942:71756e13c2400985d0402ed6f49613d0
33 | paths:
34 | - /v2/pet
35 | - /v2/address
36 | - /v2/party
37 |
38 | # apikey.yml
39 | apikey.pathPrefixAuths:
40 | - pathPrefix: /v1/test1
41 | headerName: x-gateway-apikey
42 | apiKey: abcdefg
43 | - pathPrefix: /v1/test2
44 | headerName: x-apikey
45 | apiKey: CRYPT:3ddd6c8b9bf2afc24d1c94af1dffd518:1bf0cafb19c53e61ddeae626f8906d43
46 |
47 | # client.yml
48 | client.tokenKeyServerUrl: http://localhost:7082
49 | client.tokenKeyUri: /oauth2/N2CMw0HGQXeLvC1wBfln2A/keys
50 | client.tokenKeyClientId: f7d42348-c647-4efb-a52d-4c5787421e72
51 | client.tokenKeyClientSecret: f6h1FTI8Q3-7UScPZDzfXA
52 | client.tokenKeyEnableHttp2: false
53 | client.timeout: 60000
54 |
55 | # security.yml
56 | security.skipPathPrefixes:
57 | - /oauth2
58 |
--------------------------------------------------------------------------------
/openapi-security/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | TODO create logger for audit only.
20 | http://stackoverflow.com/questions/2488558/logback-to-log-different-messages-to-two-files
21 |
22 | PROFILER
23 |
24 | NEUTRAL
25 |
26 |
27 |
28 |
30 |
31 | %d{HH:mm:ss.SSS} [%thread] %-5level %class{36}:%L %M - %msg%n
32 |
33 |
34 |
35 |
36 | target/test.log
37 | false
38 |
39 | %d{HH:mm:ss.SSS} [%thread] %-5level %class{36}:%L %M - %msg%n
40 |
41 |
42 |
43 |
44 |
45 | target/audit.log
46 |
47 | %-5level [%thread] %date{ISO8601} %F:%L - %msg%n
48 | true
49 |
50 |
51 | target/audit.log.%i.zip
52 | 1
53 | 5
54 |
55 |
56 | 200MB
57 |
58 |
59 |
60 |
61 |
62 |
63 |
75 |
76 |
--------------------------------------------------------------------------------
/openapi-validator/pom.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
19 | 4.0.0
20 |
21 |
22 | com.networknt
23 | light-rest-4j
24 | 2.2.3-SNAPSHOT
25 | ../pom.xml
26 |
27 |
28 | openapi-validator
29 | jar
30 | openapi-validator
31 | An OpenAPI specification 3.0 handler that validates request based on specification.
32 |
33 |
34 |
35 | com.networknt
36 | config
37 |
38 |
39 | com.networknt
40 | dump
41 |
42 |
43 | com.networknt
44 | json-overlay
45 |
46 |
47 | com.networknt
48 | openapi-parser
49 |
50 |
51 | com.networknt
52 | openapi-meta
53 |
54 |
55 | com.networknt
56 | openapi-security
57 |
58 |
59 | com.networknt
60 | body
61 |
62 |
63 | com.networknt
64 | handler
65 |
66 |
67 | com.networknt
68 | validator-config
69 |
70 |
71 | io.undertow
72 | undertow-core
73 |
74 |
75 | com.networknt
76 | json-schema-validator
77 |
78 |
79 | com.fasterxml.jackson.core
80 | jackson-core
81 |
82 |
83 | com.fasterxml.jackson.core
84 | jackson-databind
85 |
86 |
87 | com.fasterxml.jackson.core
88 | jackson-annotations
89 |
90 |
91 | org.slf4j
92 | slf4j-api
93 |
94 |
95 | org.owasp.encoder
96 | encoder
97 |
98 |
99 |
100 | com.networknt
101 | client
102 | test
103 |
104 |
105 | com.networknt
106 | common
107 | test
108 |
109 |
110 | ch.qos.logback
111 | logback-classic
112 | test
113 |
114 |
115 | junit
116 | junit
117 | test
118 |
119 |
120 | org.mockito
121 | mockito-core
122 | test
123 |
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/openapi-validator/src/main/java/com/networknt/openapi/SchemaValidator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Network New Technologies Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.networknt.openapi;
18 |
19 | import com.fasterxml.jackson.databind.JsonNode;
20 | import com.fasterxml.jackson.databind.node.ObjectNode;
21 | import com.networknt.jsonoverlay.Overlay;
22 | import com.networknt.oas.model.OpenApi3;
23 | import com.networknt.oas.model.impl.OpenApi3Impl;
24 | import com.networknt.schema.*;
25 | import com.networknt.status.Status;
26 |
27 | import java.util.Set;
28 |
29 | import static java.util.Objects.requireNonNull;
30 |
31 | /**
32 | * Validate a value against the schema defined in an OpenAPI specification.
33 | *
34 | * Supports validation of properties and request/response bodies, and supports schema references.
35 | *
36 | * @author Steve Hu
37 | */
38 | public class SchemaValidator {
39 | private static final String COMPONENTS_FIELD = "components";
40 | static final String VALIDATOR_SCHEMA_INVALID_JSON = "ERR11003";
41 | static final String VALIDATOR_SCHEMA = "ERR11004";
42 |
43 | private final OpenApi3 api;
44 | private JsonNode jsonNode;
45 | private final SchemaValidatorsConfig defaultConfig;
46 |
47 | /**
48 | * Build a new validator with no API specification.
49 | *
50 | * This will not perform any validation of $ref references that reference local schemas.
51 | *
52 | */
53 | public SchemaValidator() {
54 | this(null);
55 | }
56 |
57 | /**
58 | * Build a new validator with an API specification.
59 | *
60 | * This will not perform any validation of $ref references that reference local schemas.
61 | *
62 | */
63 | public SchemaValidator(final OpenApi3 api) {
64 | this(api, false);
65 | }
66 |
67 | /**
68 | * Build a new validator for the given API specification.
69 | *
70 | * @param api The API to build the validator for. If provided, is used to retrieve schemas in components
71 | * for use in references.
72 | */
73 | public SchemaValidator(final OpenApi3 api, final boolean legacyPathType) {
74 | this.api = api;
75 | this.jsonNode = Overlay.toJson((OpenApi3Impl)api).get("components");
76 | this.defaultConfig = SchemaValidatorsConfig.builder()
77 | .typeLoose(true)
78 | .pathType(legacyPathType ? PathType.LEGACY : PathType.JSON_POINTER)
79 | .build();
80 | }
81 |
82 | /**
83 | * Validate the given value against the given property schema.
84 | *
85 | * @param value The value to validate
86 | * @param schema The property schema to validate the value against
87 | * @param config The config model for some validator
88 | *
89 | * @return A status containing error code and description
90 | */
91 | public Status validate(final JsonNode value, final JsonNode schema, SchemaValidatorsConfig config) {
92 | return doValidate(value, schema, config, null);
93 | }
94 |
95 | /**
96 | * Validate the given value against the given property schema.
97 | *
98 | * @param value The value to validate
99 | * @param schema The property schema to validate the value against
100 | * @param config The config model for some validator
101 | * @param instanceLocation The location being validated
102 | * @return Status object
103 | */
104 | public Status validate(final JsonNode value, final JsonNode schema, SchemaValidatorsConfig config, JsonNodePath instanceLocation) {
105 | return doValidate(value, schema, config, instanceLocation);
106 | }
107 |
108 | public Status validate(final JsonNode value, final JsonNode schema, String at) {
109 | JsonNodePath instanceLocation = new JsonNodePath(defaultConfig.getPathType());
110 | if (at != null) {
111 | instanceLocation = instanceLocation.append(at);
112 | }
113 | return validate(value, schema, defaultConfig, instanceLocation);
114 | }
115 |
116 | public Status validate(final JsonNode value, final JsonNode schema, JsonNodePath instanceLocation) {
117 | return doValidate(value, schema, defaultConfig, instanceLocation);
118 | }
119 |
120 | private Status doValidate(final JsonNode value, final JsonNode schema, SchemaValidatorsConfig config, JsonNodePath instanceLocation) {
121 | requireNonNull(schema, "A schema is required");
122 | if (instanceLocation == null)
123 | instanceLocation = new JsonNodePath(config.getPathType());
124 |
125 | Status status = null;
126 | Set processingReport = null;
127 | try {
128 | if(jsonNode != null) {
129 | ((ObjectNode)schema).set(COMPONENTS_FIELD, jsonNode);
130 | }
131 | JsonSchema jsonSchema = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012).getSchema(schema, config);
132 | processingReport = jsonSchema.validate(jsonSchema.createExecutionContext(), value, value, instanceLocation);
133 | } catch (Exception e) {
134 | e.printStackTrace();
135 | }
136 |
137 | if(processingReport != null && !processingReport.isEmpty()) {
138 | ValidationMessage vm = processingReport.iterator().next();
139 | status = new Status(VALIDATOR_SCHEMA, vm.getMessage());
140 | }
141 |
142 | return status;
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/openapi-validator/src/main/resources/messages.properties:
--------------------------------------------------------------------------------
1 |
2 | #
3 | # Copyright (c) 2016 Network New Technologies Inc.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 | #
17 |
18 | validation.request.path.missing=No API path found that matches request '%s'.
19 | validation.request.operation.notAllowed=%s operation not allowed on path '%s'.
20 | validation.request.body.unexpected=No request body is expected for %s on path '%s'.
21 | validation.request.body.missing=%s on path '%s' requires a request body. None found.
22 | validation.request.parameter.missing=Parameter '%s' is required but is missing.
23 | validation.request.parameter.query.missing=Query parameter '%s' is required on path '%s' but not found in request.
24 |
25 | validation.response.status.unknown=Response status %d not defined for path '%s'.
26 | validation.response.body.missing=%s on path '%s' defines a response schema but no response body found.
27 | validation.schema.invalidJson=Unable to parse JSON - %s
28 |
--------------------------------------------------------------------------------
/openapi-validator/src/test/java/com/networknt/openapi/ForwardRequestHandler.java:
--------------------------------------------------------------------------------
1 | package com.networknt.openapi;
2 |
3 | import com.networknt.common.ContentType;
4 | import com.networknt.config.Config;
5 | import com.networknt.handler.LightHttpHandler;
6 | import com.networknt.httpstring.AttachmentConstants;
7 |
8 | import io.undertow.server.HttpServerExchange;
9 | import io.undertow.util.Headers;
10 | import io.undertow.util.HttpString;
11 |
12 | import java.util.List;
13 | import java.util.stream.Collectors;
14 |
15 | public class ForwardRequestHandler implements LightHttpHandler {
16 |
17 | @Override
18 | public void handleRequest(HttpServerExchange exchange) throws Exception {
19 | String responseBody = null;
20 | if(exchange.getAttachment(AttachmentConstants.REQUEST_BODY) != null) {
21 | responseBody = Config.getInstance().getMapper().writeValueAsString(exchange.getAttachment(AttachmentConstants.REQUEST_BODY));
22 | }
23 |
24 | List headerNames = exchange.getRequestHeaders().getHeaderNames().stream()
25 | .filter( s -> s.toString().startsWith("todo"))
26 | .collect(Collectors.toList());
27 | for(HttpString headerName : headerNames) {
28 | String headerValue = exchange.getRequestHeaders().get(headerName).getFirst();
29 | exchange.getResponseHeaders().put(headerName, headerValue);
30 | }
31 | exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, ContentType.APPLICATION_JSON.value());
32 | exchange.getResponseSender().send(responseBody);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/openapi-validator/src/test/java/com/networknt/openapi/ParameterHandler.java:
--------------------------------------------------------------------------------
1 | package com.networknt.openapi;
2 |
3 | import static io.undertow.util.PathTemplateMatch.ATTACHMENT_KEY;
4 |
5 | import java.util.Map;
6 |
7 | import com.networknt.handler.Handler;
8 | import com.networknt.handler.MiddlewareHandler;
9 | import com.networknt.utility.ModuleRegistry;
10 |
11 | import io.undertow.Handlers;
12 | import io.undertow.server.HttpHandler;
13 | import io.undertow.server.HttpServerExchange;
14 | import io.undertow.util.PathTemplateMatcher;
15 |
16 | /**
17 | * Simulate com.networknt.handler.Handler.start()
18 | * @author Daniel Zhao
19 | *
20 | */
21 | public class ParameterHandler implements MiddlewareHandler {
22 | private static PathTemplateMatcher pathTemplateMatcher = new PathTemplateMatcher<>();
23 | private volatile HttpHandler next;
24 |
25 | static {
26 | pathTemplateMatcher.add("/pets", "0");
27 | pathTemplateMatcher.add("/pets/{petId}", "1");
28 | pathTemplateMatcher.add("/pets_simple_array/{petId}", "2");
29 | pathTemplateMatcher.add("/pets_simple_obj_ep/{petId}", "3");
30 | pathTemplateMatcher.add("/pets_simple_obj_no_ep/{petId}", "4");
31 | pathTemplateMatcher.add("/pets_label_array_ep/{petId}", "5");
32 | pathTemplateMatcher.add("/pets_label_array_no_ep/{petId}", "6");
33 | pathTemplateMatcher.add("/pets_label_obj_ep/{petId}", "7");
34 | pathTemplateMatcher.add("/pets_label_obj_no_ep/{petId}", "8");
35 | pathTemplateMatcher.add("/pets_matrix_array_ep/{petId}", "9");
36 | pathTemplateMatcher.add("/pets_matrix_array_no_ep/{petId}", "10");
37 | pathTemplateMatcher.add("/pets_matrix_obj_ep/{petId}", "11");
38 | pathTemplateMatcher.add("/pets_matrix_obj_no_ep/{petId}", "12");
39 | pathTemplateMatcher.add("/pets_matrix_pm/{petId}", "13");
40 | }
41 |
42 | @Override
43 | public void handleRequest(HttpServerExchange exchange) throws Exception {
44 | PathTemplateMatcher.PathMatchResult result = pathTemplateMatcher.match(exchange.getRequestPath());
45 |
46 | if (result != null) {
47 | exchange.putAttachment(ATTACHMENT_KEY,
48 | new io.undertow.util.PathTemplateMatch(result.getMatchedTemplate(), result.getParameters()));
49 | for (Map.Entry entry : result.getParameters().entrySet()) {
50 | exchange.addQueryParam(entry.getKey(), entry.getValue());
51 |
52 | exchange.addPathParam(entry.getKey(), entry.getValue());
53 | }
54 | }
55 |
56 | Handler.next(exchange, next);
57 | }
58 |
59 | @Override
60 | public HttpHandler getNext() {
61 | return next;
62 | }
63 |
64 | @Override
65 | public MiddlewareHandler setNext(HttpHandler next) {
66 | Handlers.handlerNotNull(next);
67 | this.next = next;
68 | return this;
69 | }
70 |
71 | @Override
72 | public boolean isEnabled() {
73 | return true;
74 | }
75 |
76 | @Override
77 | public void register() {
78 |
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/openapi-validator/src/test/java/com/networknt/openapi/ResponseValidatorTest.java:
--------------------------------------------------------------------------------
1 | package com.networknt.openapi;
2 |
3 | import com.networknt.body.BodyHandler;
4 | import com.networknt.config.Config;
5 | import com.networknt.handler.LightHttpHandler;
6 | import com.networknt.httpstring.AttachmentConstants;
7 | import com.networknt.status.Status;
8 | import com.networknt.exception.ClientException;
9 | import io.undertow.Handlers;
10 | import io.undertow.Undertow;
11 | import io.undertow.client.ClientRequest;
12 | import io.undertow.client.ClientResponse;
13 | import io.undertow.server.HttpHandler;
14 | import io.undertow.server.HttpServerExchange;
15 | import io.undertow.util.Methods;
16 | import org.junit.AfterClass;
17 | import org.junit.Assert;
18 | import org.junit.Before;
19 | import org.junit.Test;
20 | import org.slf4j.Logger;
21 | import org.slf4j.LoggerFactory;
22 |
23 | import java.net.URISyntaxException;
24 | import java.util.Map;
25 | import java.util.concurrent.CompletableFuture;
26 | import java.util.concurrent.ExecutionException;
27 | import java.util.concurrent.TimeUnit;
28 | import java.util.concurrent.TimeoutException;
29 |
30 | import static com.networknt.openapi.ValidatorHandlerTest.sendResponse;
31 |
32 | public class ResponseValidatorTest {
33 | static Map responses = Config.getInstance().getJsonMapConfig("responses");
34 | static Undertow server = null;
35 | static final Logger logger = LoggerFactory.getLogger(ResponseValidatorTest.class);
36 | @Before
37 | public void setUp() {
38 | if(server == null) {
39 | logger.info("starting server");
40 | OpenApiHandler openApiHandler = new OpenApiHandler();
41 | BodyHandler bodyHandler = new BodyHandler();
42 |
43 | TestValidateResponseHandler testValidateResponseHandler = new TestValidateResponseHandler();
44 | HttpHandler handler = Handlers.routing()
45 | .add(Methods.GET, "/v1/todoItems", testValidateResponseHandler);
46 | ValidatorHandler validatorHandler = new ValidatorHandler();
47 | validatorHandler.setNext(handler);
48 | handler = validatorHandler;
49 |
50 | bodyHandler.setNext(handler);
51 | handler = bodyHandler;
52 |
53 | openApiHandler.setNext(handler);
54 | handler = openApiHandler;
55 |
56 | server = Undertow.builder()
57 | .addHttpListener(7080, "localhost")
58 | .setHandler(handler)
59 | .build();
60 | server.start();
61 | }
62 | }
63 |
64 | @AfterClass
65 | public static void tearDown() throws Exception {
66 | if(server != null) {
67 | try {
68 | Thread.sleep(100);
69 | } catch (InterruptedException ignored) {
70 |
71 | }
72 | server.stop();
73 | logger.info("The server is stopped.");
74 | }
75 | }
76 |
77 | @Test
78 | public void testValidateResponseContentWithExchange() throws InterruptedException, ClientException, URISyntaxException, TimeoutException, ExecutionException {
79 | ClientRequest clientRequest = new ClientRequest();
80 | CompletableFuture future = sendResponse(clientRequest, "response1");
81 | Assert.assertTrue(future.get(3, TimeUnit.SECONDS).getResponseCode() == 200);
82 | }
83 |
84 | @Test
85 | public void testValidateResponseContentWithExchangeError() throws InterruptedException, ClientException, URISyntaxException, TimeoutException, ExecutionException {
86 | ClientRequest clientRequest = new ClientRequest();
87 | CompletableFuture future = sendResponse(clientRequest, "response2");
88 | Assert.assertTrue(future.get(3, TimeUnit.SECONDS).getResponseCode() > 300);
89 | }
90 |
91 | public class TestValidateResponseHandler implements LightHttpHandler {
92 |
93 | @Override
94 | public void handleRequest(HttpServerExchange exchange) throws Exception {
95 |
96 | String responseBody = null;
97 | if(exchange.getAttachment(AttachmentConstants.REQUEST_BODY) != null) {
98 | responseBody = Config.getInstance().getMapper().writeValueAsString(exchange.getAttachment(AttachmentConstants.REQUEST_BODY));
99 | }
100 | final SchemaValidator schemaValidator = new SchemaValidator(OpenApiHandler.helper.openApi3, false);
101 | ResponseValidator validator = new ResponseValidator(schemaValidator);
102 | Status status = validator.validateResponseContent(responseBody, exchange);
103 | if(status == null) {
104 | exchange.getResponseSender().send("good");
105 | } else {
106 | exchange.setStatusCode(400);
107 | exchange.getResponseSender().send("bad");
108 | }
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/openapi-validator/src/test/resources/config/client.truststore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/networknt/light-rest-4j/27c19bbaf3ad3792007aa89dc6b8f018c52178c0/openapi-validator/src/test/resources/config/client.truststore
--------------------------------------------------------------------------------
/openapi-validator/src/test/resources/config/handler.yml:
--------------------------------------------------------------------------------
1 | ---
2 | enabled: true
3 |
4 | # Configuration for the LightHttpHandler. The handler is the base class for all middleware, server and health handlers
5 | # set the Status Object in the AUDIT_INFO, for auditing purposes
6 | # default, if not set:false
7 | auditOnError: true
8 |
9 | # set the StackTrace in the AUDIT_INFO, for auditing purposes
10 | # default, if not set:false
11 | auditStackTrace: true
12 |
13 | handlers:
14 | - com.networknt.handler.sample.SampleHttpHandler1
15 | - com.networknt.handler.sample.SampleHttpHandler2
16 | - com.networknt.handler.sample.SampleHttpHandler3@third
17 |
18 | chains:
19 | secondBeforeFirst:
20 | - com.networknt.handler.sample.SampleHttpHandler2
21 | - com.networknt.handler.sample.SampleHttpHandler1
22 |
23 | paths:
24 | - path: '/test'
25 | method: 'get'
26 | exec:
27 | - secondBeforeFirst
28 | - third
29 | - path: '/v2/health'
30 | method: 'post'
31 | exec:
32 | - secondBeforeFirst
33 | - third
34 | # If there is no matched path, then it goes here first. If this is not set, then an error
35 | # will be returned.
36 | defaultHandlers:
37 | - third
38 |
--------------------------------------------------------------------------------
/openapi-validator/src/test/resources/config/openapi-handler-enum.yml:
--------------------------------------------------------------------------------
1 | # openapi-handler.yml
2 | # This configuration file is used to support multiple OpenAPI specifications in the same light-rest-4j instance.
3 | # An indicator to allow multiple openapi specifications. Default to false which only allow one spec named openapi.yml or openapi.yaml or openapi.json.
4 | multipleSpec: ${openapi-handler.multipleSpec:true}
5 | # Path to spec mapping. One or more base paths can map to the same specifications. The key is the base path and the value is the specification name.
6 | # If users want to use multiple specification files in the same instance, each specification must have a unique base path and it must be set as key.
7 | pathSpecMapping:
8 | /v1: openapi-enum
9 |
--------------------------------------------------------------------------------
/openapi-validator/src/test/resources/config/openapi-handler-multiple.yml:
--------------------------------------------------------------------------------
1 | # openapi-handler.yml
2 | # This configuration file is used to support multiple OpenAPI specifications in the same light-rest-4j instance.
3 | # An indicator to allow multiple openapi specifications. Default to false which only allow one spec named openapi.yml or openapi.yaml or openapi.json.
4 | multipleSpec: ${openapi-handler.multipleSpec:true}
5 | # Path to spec mapping. One or more base paths can map to the same specifications. The key is the base path and the value is the specification name.
6 | # If users want to use multiple specification files in the same instance, each specification must have a unique base path and it must be set as key.
7 | pathSpecMapping:
8 | /petstore: openapi-petstore
9 | /market: openapi-market
10 |
--------------------------------------------------------------------------------
/openapi-validator/src/test/resources/config/openapi-market.yaml:
--------------------------------------------------------------------------------
1 | openapi: 3.0.0
2 | info:
3 | version: 1.0.0
4 | title: Swagger Market
5 | license:
6 | name: MIT
7 | servers:
8 | - url: 'http://market.swagger.io/market'
9 | paths:
10 | /{store}/products:
11 | get:
12 | summary: Get all products from stores
13 | operationId: listProducts
14 | tags:
15 | - products
16 | parameters:
17 | - name: limit
18 | in: query
19 | description: How many items to return at one time (max 100)
20 | required: false
21 | schema:
22 | type: integer
23 | format: int32
24 | - name: store
25 | in: path
26 | description: The downstream store name
27 | required: true
28 | schema:
29 | type: string
30 | security:
31 | - market_auth:
32 | - 'read:products'
33 | responses:
34 | '200':
35 | description: An paged array of products
36 | content:
37 | application/json:
38 | schema:
39 | type: array
40 | items:
41 | $ref: '#/components/schemas/Product'
42 | example:
43 | - id: 1
44 | name: catten
45 | tag: cat
46 | - id: 2
47 | name: doggy
48 | tag: dog
49 | default:
50 | description: unexpected error
51 | content:
52 | application/json:
53 | schema:
54 | $ref: '#/components/schemas/Error'
55 | post:
56 | summary: Create a product
57 | operationId: createProducts
58 | parameters:
59 | - name: store
60 | in: path
61 | description: The downstream store name
62 | required: true
63 | schema:
64 | type: string
65 | requestBody:
66 | description: Product to add to the target store
67 | required: true
68 | content:
69 | application/json:
70 | schema:
71 | $ref: '#/components/schemas/Product'
72 | tags:
73 | - products
74 | security:
75 | - market_auth:
76 | - 'read:products'
77 | - 'write:products'
78 | responses:
79 | '201':
80 | description: Null response
81 | default:
82 | description: unexpected error
83 | content:
84 | application/json:
85 | schema:
86 | $ref: '#/components/schemas/Error'
87 | components:
88 | securitySchemes:
89 | market_auth:
90 | type: oauth2
91 | description: This API uses OAuth 2 with the client credential grant flow.
92 | flows:
93 | clientCredentials:
94 | tokenUrl: 'https://localhost:6882/token'
95 | scopes:
96 | 'write:products': modify products
97 | 'read:products': read your products
98 | schemas:
99 | Product:
100 | type: object
101 | required:
102 | - id
103 | - name
104 | properties:
105 | id:
106 | type: integer
107 | format: int64
108 | name:
109 | type: string
110 | tag:
111 | type: string
112 | Error:
113 | type: object
114 | required:
115 | - code
116 | - message
117 | properties:
118 | code:
119 | type: integer
120 | format: int32
121 | message:
122 | type: string
123 |
--------------------------------------------------------------------------------
/openapi-validator/src/test/resources/config/openapi-validator.yml:
--------------------------------------------------------------------------------
1 | # This is specific OpenAPI validator configuration file. It is introduced to support multiple
2 | # frameworks in the same server instance and it is recommended. If this file cannot be found,
3 | # the generic validator.yml will be loaded as a fallback.
4 | ---
5 | # Enable request validation. Response validation is not done on the server but client.
6 | enabled: true
7 | # Log error message if validation error occurs
8 | logError: true
9 | # Skip body validation set to true if used in light-router, light-proxy and light-spring-boot.
10 | skipBodyValidation: false
11 | validateResponse: true
12 |
13 | # When a field is set as nullable in the OpenAPI specification, the schema validator validates that it is nullable
14 | # however continues with validation against the nullable field
15 |
16 | # If handleNullableField is set to true && incoming field is nullable && value is field: null --> succeed
17 | # If handleNullableField is set to false && incoming field is nullable && value is field: null --> it is up to the type
18 | # validator using the SchemaValidator to handle it.
19 | handleNullableField: true
20 |
--------------------------------------------------------------------------------
/openapi-validator/src/test/resources/config/responses.yml:
--------------------------------------------------------------------------------
1 | response1:
2 | - id: 1a7f12c2-f591-4344-9c93-56d16cfdb0ce
3 | content: response1
4 | trace: 1
5 | - id: 1b7f12c2-f591-4344-9c93-56d16cfdb0ce
6 | content: response1
7 | trace: 2
8 | response2:
9 | - id: 2a7f12c2-f591-4344-9c93-56d16cfdb0ce
10 | trace: 3
11 |
--------------------------------------------------------------------------------
/openapi-validator/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | TODO create logger for audit only.
20 | http://stackoverflow.com/questions/2488558/logback-to-log-different-messages-to-two-files
21 |
22 | PROFILER
23 |
24 | NEUTRAL
25 |
26 |
27 |
28 |
30 |
31 | %d{HH:mm:ss.SSS} [%thread] %-5marker %-5level %logger{36} - %msg%n
32 |
33 |
34 |
35 |
36 | target/test.log
37 | false
38 |
39 | %d{HH:mm:ss.SSS} [%thread] %-5level %class{36}:%L %M - %msg%n
40 |
41 |
42 |
43 |
44 |
45 | target/audit.log
46 |
47 | %-5level [%thread] %date{ISO8601} %F:%L - %msg%n
48 | true
49 |
50 |
51 | target/audit.log.%i.zip
52 | 1
53 | 5
54 |
55 |
56 | 200MB
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/specification/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | light-rest-4j
7 | com.networknt
8 | 2.2.3-SNAPSHOT
9 |
10 | 4.0.0
11 | jar
12 | specification
13 | specification
14 |
15 |
16 |
17 | com.networknt
18 | config
19 |
20 |
21 | com.networknt
22 | utility
23 |
24 |
25 | com.networknt
26 | security
27 |
28 |
29 | com.networknt
30 | handler
31 |
32 |
33 | com.networknt
34 | status
35 |
36 |
37 | io.undertow
38 | undertow-core
39 |
40 |
41 | com.fasterxml.jackson.core
42 | jackson-databind
43 |
44 |
45 | org.slf4j
46 | slf4j-api
47 |
48 |
49 |
50 | com.networknt
51 | client
52 | test
53 |
54 |
55 | ch.qos.logback
56 | logback-classic
57 | test
58 |
59 |
60 | junit
61 | junit
62 | test
63 |
64 |
65 | org.apache.commons
66 | commons-text
67 | test
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/specification/src/main/java/com/networknt/specification/FaviconHandler.java:
--------------------------------------------------------------------------------
1 | package com.networknt.specification;
2 |
3 | import com.networknt.config.Config;
4 | import com.networknt.handler.LightHttpHandler;
5 | import io.undertow.server.HttpServerExchange;
6 | import io.undertow.util.HttpString;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import java.io.InputStream;
11 | import java.io.OutputStream;
12 |
13 | /**
14 | * This is the handler that returns the favicon.ico from the resources config folder for
15 | * swagger ui rendering.
16 | *
17 | * @author Steve Hu
18 | */
19 | public class FaviconHandler implements LightHttpHandler {
20 | private static final Logger logger = LoggerFactory.getLogger(FaviconHandler.class);
21 | public FaviconHandler(){
22 | if(logger.isInfoEnabled()) logger.info("FaviconHandler is initialized.");
23 | }
24 |
25 | @Override
26 | public void handleRequest(HttpServerExchange exchange) throws Exception {
27 | if (exchange.isInIoThread()) {
28 | exchange.dispatch(this);
29 | return;
30 | }
31 | exchange.startBlocking();
32 | exchange.getResponseHeaders().add(new HttpString("Content-Type"), "image/x-icon");
33 | try (InputStream inputStream = Config.getInstance().getInputStreamFromFile("favicon.ico"); OutputStream outputStream = exchange.getOutputStream()) {
34 | byte[] buf = new byte[8192];
35 | int c;
36 | while ((c = inputStream.read(buf, 0, buf.length)) > 0) {
37 | outputStream.write(buf, 0, c);
38 | outputStream.flush();
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/specification/src/main/java/com/networknt/specification/SpecDisplayHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Network New Technologies Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.networknt.specification;
18 |
19 | import com.networknt.config.Config;
20 | import com.networknt.handler.LightHttpHandler;
21 | import com.networknt.utility.ModuleRegistry;
22 | import io.undertow.server.HttpServerExchange;
23 | import io.undertow.util.HttpString;
24 |
25 | /**
26 | * Display API Specification
27 | *
28 | * @author Gavin Chen
29 | */
30 | public class SpecDisplayHandler implements LightHttpHandler {
31 | static SpecificationConfig config = (SpecificationConfig)Config.getInstance().getJsonObjectConfig(SpecificationConfig.CONFIG_NAME, SpecificationConfig.class);
32 | public SpecDisplayHandler(){
33 | if(logger.isInfoEnabled()) logger.info("SpecDisplayHandler is constructed");
34 | ModuleRegistry.registerModule(SpecificationConfig.CONFIG_NAME, SpecDisplayHandler.class.getName(), Config.getNoneDecryptedInstance().getJsonMapConfigNoCache(SpecificationConfig.CONFIG_NAME), null);
35 | }
36 |
37 | @Override
38 | public void handleRequest(HttpServerExchange exchange) throws Exception {
39 | SpecificationConfig config = (SpecificationConfig)Config.getInstance().getJsonObjectConfig(SpecificationConfig.CONFIG_NAME, SpecificationConfig.class);
40 | final String payload = Config.getInstance().getStringFromFile(config.getFileName());
41 | exchange.getResponseHeaders().add(new HttpString("Content-Type"), config.getContentType());
42 | exchange.getResponseSender().send(payload);
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/specification/src/main/java/com/networknt/specification/SpecSwaggerUIHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Network New Technologies Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.networknt.specification;
18 | import com.networknt.config.Config;
19 | import com.networknt.handler.LightHttpHandler;
20 | import io.undertow.server.HttpServerExchange;
21 | import io.undertow.util.HttpString;
22 |
23 | /**
24 | * Display API Specification in Swagger editor UI
25 | *
26 | * @author Gavin Chen
27 | */
28 | public class SpecSwaggerUIHandler implements LightHttpHandler {
29 | // The url in this html is using the spec.yaml API which is served by SpecDisplayHandler. It needs to be in sync with the handler.yml
30 | public static String swaggerUITemplate =
31 | "\n" +
32 | "\n" +
33 | " OpenAPI Spec\n" +
34 | " \n" +
35 | "\n" +
36 | "\n" +
37 | "\n" +
38 | "\n" +
39 | "\n" +
40 | "\n" +
61 | "\n" +
62 | "";
63 | public SpecSwaggerUIHandler(){}
64 |
65 |
66 |
67 | @Override
68 | public void handleRequest(HttpServerExchange exchange) throws Exception {
69 | SpecificationConfig config = (SpecificationConfig) Config.getInstance().getJsonObjectConfig(SpecificationConfig.CONFIG_NAME, SpecificationConfig.class);
70 | exchange.getResponseHeaders().add(new HttpString("Content-Type"), "text/html");
71 | exchange.getResponseSender().send(getDisplayHtml());
72 | }
73 |
74 | private String getDisplayHtml() {
75 | return swaggerUITemplate;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/specification/src/main/java/com/networknt/specification/SpecificationConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Network New Technologies Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.networknt.specification;
18 |
19 | import com.networknt.config.schema.ConfigSchema;
20 | import com.networknt.config.schema.OutputFormat;
21 | import com.networknt.config.schema.StringField;
22 |
23 | /**
24 | * Config class for Spec display Handler
25 | *
26 | */
27 | @ConfigSchema(
28 | configName = "specification",
29 | configKey = "specification",
30 | configDescription = "Specification type and file name definition",
31 | outputFormats = {OutputFormat.JSON_SCHEMA, OutputFormat.YAML}
32 | )
33 | public class SpecificationConfig {
34 | public static final String CONFIG_NAME = "specification";
35 | public static final String FILE_NAME = "fileName";
36 | public static final String CONTENT_TYPE = "contentType";
37 |
38 | @StringField(
39 | configFieldName = FILE_NAME,
40 | externalizedKeyName = FILE_NAME,
41 | externalized = true,
42 | defaultValue = "openapi.yaml",
43 | description = "The filename with path of the specification file, and usually it is openapi.yaml"
44 | )
45 | String fileName;
46 |
47 | @StringField(
48 | configFieldName = CONTENT_TYPE,
49 | externalizedKeyName = CONTENT_TYPE,
50 | externalized = true,
51 | defaultValue = "text/yaml",
52 | description = "The content type of the specification file. In most cases, we are using yaml format."
53 | )
54 | String contentType;
55 |
56 | public SpecificationConfig() {
57 | }
58 |
59 | public String getFileName() {
60 | return fileName;
61 | }
62 |
63 | public void setFileName(String fileName) {
64 | this.fileName = fileName;
65 | }
66 |
67 | public String getContentType() {
68 | return contentType;
69 | }
70 |
71 | public void setContentType(String contentType) {
72 | this.contentType = contentType;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/specification/src/main/resources/config/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/networknt/light-rest-4j/27c19bbaf3ad3792007aa89dc6b8f018c52178c0/specification/src/main/resources/config/favicon.ico
--------------------------------------------------------------------------------
/specification/src/main/resources/config/specification-schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema" : "http://json-schema.org/draft-07/schema#",
3 | "type" : "object",
4 | "required" : [ "fileName", "contentType" ],
5 | "properties" : {
6 | "fileName" : {
7 | "type" : "string",
8 | "description" : "The filename with path of the specification file, and usually it is openapi.yaml",
9 | "default" : "openapi.yaml"
10 | },
11 | "contentType" : {
12 | "type" : "string",
13 | "description" : "The content type of the specification file. In most cases, we are using yaml format.",
14 | "default" : "text/yaml"
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/specification/src/main/resources/config/specification.yaml:
--------------------------------------------------------------------------------
1 | # Specification type and file name definition
2 | # The filename with path of the specification file, and usually it is openapi.yaml
3 | fileName: ${specification.fileName:openapi.yaml}
4 | # The content type of the specification file. In most cases, we are using yaml format.
5 | contentType: ${specification.contentType:text/yaml}
6 |
--------------------------------------------------------------------------------
/specification/src/main/resources/config/specification.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Specification type and file name definition
3 | # The filename with path of the specification file, and usually it is openapi.yaml
4 | fileName: ${specification.fileName:openapi.yaml}
5 | # The content type of the specification file. In most cases, we are using yaml format.
6 | contentType: ${specification.contentType:text/yaml}
7 |
--------------------------------------------------------------------------------
/specification/src/test/java/com/networknt/specification/SpecDisplayHandlerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Network New Technologies Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.networknt.specification;
18 |
19 | import com.networknt.client.Http2Client;
20 | import com.networknt.exception.ClientException;
21 | import io.undertow.Handlers;
22 | import io.undertow.Undertow;
23 | import io.undertow.client.ClientConnection;
24 | import io.undertow.client.ClientRequest;
25 | import io.undertow.client.ClientResponse;
26 | import io.undertow.server.HttpHandler;
27 | import io.undertow.server.RoutingHandler;
28 | import io.undertow.util.Headers;
29 | import io.undertow.util.Methods;
30 | import org.junit.AfterClass;
31 | import org.junit.Assert;
32 | import org.junit.BeforeClass;
33 | import org.junit.Test;
34 | import org.slf4j.Logger;
35 | import org.slf4j.LoggerFactory;
36 | import org.xnio.IoUtils;
37 | import org.xnio.OptionMap;
38 |
39 | import java.net.URI;
40 | import java.util.concurrent.CountDownLatch;
41 | import java.util.concurrent.atomic.AtomicReference;
42 |
43 | /**
44 | * Created by Gavin Chen.
45 | */
46 | public class SpecDisplayHandlerTest {
47 | static final Logger logger = LoggerFactory.getLogger(SpecDisplayHandlerTest.class);
48 |
49 | static Undertow server = null;
50 |
51 | @BeforeClass
52 | public static void setUp() {
53 | if(server == null) {
54 | logger.info("starting server");
55 | HttpHandler handler = getTestHandler();
56 | server = Undertow.builder()
57 | .addHttpListener(7080, "localhost")
58 | .setHandler(handler)
59 | .build();
60 | server.start();
61 | }
62 | }
63 |
64 | @AfterClass
65 | public static void tearDown() throws Exception {
66 | if(server != null) {
67 | try {
68 | Thread.sleep(100);
69 | } catch (InterruptedException ignored) {
70 |
71 | }
72 | server.stop();
73 | logger.info("The server is stopped.");
74 | }
75 | }
76 |
77 | static RoutingHandler getTestHandler() {
78 | return Handlers.routing().add(Methods.GET, "/spec.yml", new SpecDisplayHandler());
79 | }
80 |
81 | @Test
82 | public void testSpec() throws Exception {
83 | final Http2Client client = Http2Client.getInstance();
84 | final CountDownLatch latch = new CountDownLatch(1);
85 | final ClientConnection connection;
86 | try {
87 | connection = client.connect(new URI("http://localhost:7080"), Http2Client.WORKER, Http2Client.SSL, Http2Client.BUFFER_POOL, OptionMap.EMPTY).get();
88 | } catch (Exception e) {
89 | throw new ClientException(e);
90 | }
91 | final AtomicReference reference = new AtomicReference<>();
92 | try {
93 | ClientRequest request = new ClientRequest().setPath("/spec.yml").setMethod(Methods.GET);
94 | request.getRequestHeaders().put(Headers.HOST, "localhost");
95 | connection.sendRequest(request, client.createClientCallback(reference, latch));
96 | latch.await();
97 | } catch (Exception e) {
98 | logger.error("Exception: ", e);
99 | throw new ClientException(e);
100 | } finally {
101 | IoUtils.safeClose(connection);
102 | }
103 | int statusCode = reference.get().getResponseCode();
104 | String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY);
105 | Assert.assertEquals(200, statusCode);
106 | Assert.assertNotNull( body);
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/specification/src/test/java/com/networknt/specification/SpecSwaggerUIHandlerTest.java:
--------------------------------------------------------------------------------
1 | package com.networknt.specification;
2 |
3 | import com.networknt.client.Http2Client;
4 | import com.networknt.exception.ClientException;
5 | import io.undertow.Handlers;
6 | import io.undertow.Undertow;
7 | import io.undertow.client.ClientConnection;
8 | import io.undertow.client.ClientRequest;
9 | import io.undertow.client.ClientResponse;
10 | import io.undertow.server.HttpHandler;
11 | import io.undertow.server.RoutingHandler;
12 | import io.undertow.util.Headers;
13 | import io.undertow.util.Methods;
14 | import org.junit.AfterClass;
15 | import org.junit.Assert;
16 | import org.junit.BeforeClass;
17 | import org.junit.Test;
18 | import org.slf4j.Logger;
19 | import org.slf4j.LoggerFactory;
20 | import org.xnio.IoUtils;
21 | import org.xnio.OptionMap;
22 |
23 | import java.net.URI;
24 | import java.util.concurrent.CountDownLatch;
25 | import java.util.concurrent.atomic.AtomicReference;
26 |
27 | public class SpecSwaggerUIHandlerTest {
28 | static final Logger logger = LoggerFactory.getLogger(SpecSwaggerUIHandlerTest.class);
29 |
30 | static Undertow server = null;
31 |
32 | @BeforeClass
33 | public static void setUp() {
34 | if(server == null) {
35 | logger.info("starting server");
36 | HttpHandler handler = getTestHandler();
37 | server = Undertow.builder()
38 | .addHttpListener(7080, "localhost")
39 | .setHandler(handler)
40 | .build();
41 | server.start();
42 | }
43 | }
44 |
45 | @AfterClass
46 | public static void tearDown() throws Exception {
47 | if(server != null) {
48 | try {
49 | Thread.sleep(100);
50 | } catch (InterruptedException ignored) {
51 |
52 | }
53 | server.stop();
54 | logger.info("The server is stopped.");
55 | }
56 | }
57 |
58 | static RoutingHandler getTestHandler() {
59 | return Handlers.routing().add(Methods.GET, "/specui.html", new SpecSwaggerUIHandler());
60 | }
61 |
62 | @Test
63 | public void testSpecUI() throws Exception {
64 | final Http2Client client = Http2Client.getInstance();
65 | final CountDownLatch latch = new CountDownLatch(1);
66 | final ClientConnection connection;
67 | try {
68 | connection = client.connect(new URI("http://localhost:7080"), Http2Client.WORKER, Http2Client.SSL, Http2Client.BUFFER_POOL, OptionMap.EMPTY).get();
69 | } catch (Exception e) {
70 | throw new ClientException(e);
71 | }
72 | final AtomicReference reference = new AtomicReference<>();
73 | try {
74 | ClientRequest request = new ClientRequest().setPath("/specui.html").setMethod(Methods.GET);
75 | request.getRequestHeaders().put(Headers.HOST, "localhost");
76 | connection.sendRequest(request, client.createClientCallback(reference, latch));
77 | latch.await();
78 | } catch (Exception e) {
79 | logger.error("Exception: ", e);
80 | throw new ClientException(e);
81 | } finally {
82 | IoUtils.safeClose(connection);
83 | }
84 | int statusCode = reference.get().getResponseCode();
85 | String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY);
86 | Assert.assertEquals(200, statusCode);
87 | Assert.assertNotNull( body);
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/specification/src/test/resources/config/client.truststore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/networknt/light-rest-4j/27c19bbaf3ad3792007aa89dc6b8f018c52178c0/specification/src/test/resources/config/client.truststore
--------------------------------------------------------------------------------
/specification/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | TODO create logger for audit only.
20 | http://stackoverflow.com/questions/2488558/logback-to-log-different-messages-to-two-files
21 |
22 | PROFILER
23 |
24 | NEUTRAL
25 |
26 |
27 |
28 |
30 |
31 | %d{HH:mm:ss.SSS} [%thread] %-5marker %-5level %logger{36} - %msg%n
32 |
33 |
34 |
35 |
36 | target/test.log
37 | false
38 |
39 | %d{HH:mm:ss.SSS} [%thread] %-5level %class{36}:%L %M - %msg%n
40 |
41 |
42 |
43 |
44 |
45 | target/audit.log
46 |
47 | %-5level [%thread] %date{ISO8601} %F:%L - %msg%n
48 | true
49 |
50 |
51 | target/audit.log.%i.zip
52 | 1
53 | 5
54 |
55 |
56 | 200MB
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/validator-config/pom.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
19 | 4.0.0
20 |
21 |
22 | com.networknt
23 | light-rest-4j
24 | 2.2.3-SNAPSHOT
25 | ../pom.xml
26 |
27 |
28 | validator-config
29 | jar
30 | validator-config
31 | A config module for openapi-validator and light-aws-lambda.
32 |
33 |
34 |
35 | com.networknt
36 | config
37 |
38 |
39 | org.slf4j
40 | slf4j-api
41 |
42 |
43 |
44 | ch.qos.logback
45 | logback-classic
46 | test
47 |
48 |
49 | junit
50 | junit
51 | test
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/validator-config/src/main/resources/config/openapi-validator-schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema" : "http://json-schema.org/draft-07/schema#",
3 | "type" : "object",
4 | "required" : [ "enabled", "logError", "legacyPathType", "skipBodyValidation", "validateResponse", "handleNullableField", "skipPathPrefixes" ],
5 | "properties" : {
6 | "enabled" : {
7 | "type" : "boolean",
8 | "description" : "Enable request validation. Response validation is not done on the server but client.",
9 | "default" : true
10 | },
11 | "logError" : {
12 | "type" : "boolean",
13 | "description" : "Log error message if validation error occurs",
14 | "default" : true
15 | },
16 | "legacyPathType" : {
17 | "type" : "boolean",
18 | "description" : "By default, the json-schema-validator will return the error message using JSON_POINTER path type. If you want\nto make sure that the error message is the same as the older version, you can set the legacyPathType to true."
19 | },
20 | "skipBodyValidation" : {
21 | "type" : "boolean",
22 | "description" : "Skip body validation set to true if used in light-router, light-proxy and light-spring-boot."
23 | },
24 | "validateResponse" : {
25 | "type" : "boolean",
26 | "description" : "Enable response validation."
27 | },
28 | "handleNullableField" : {
29 | "type" : "boolean",
30 | "description" : "When a field is set as nullable in the OpenAPI specification, the schema validator validates that it is nullable\nhowever continues with validation against the nullable field\n\nIf handleNullableField is set to true && incoming field is nullable && value is field: null --> succeed\nIf handleNullableField is set to false && incoming field is nullable && value is field: null --> it is up to the type\nvalidator using the SchemaValidator to handle it.",
31 | "default" : true
32 | },
33 | "skipPathPrefixes" : {
34 | "type" : "array",
35 | "description" : "Define a list of path prefixes to skip the validation to ease the configuration for the\nhandler.yml so that users can define some endpoints without validation even through it uses\nthe default chain. This is particularly useful in the light-gateway use case as the same\ninstance might be shared with multiple consumers and providers with different validation\nrequirement. The format is a list of strings separated with commas or a JSON list in\nvalues.yml definition from config server, or you can use yaml format in this file.",
36 | "items" : {
37 | "type" : "string"
38 | }
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/validator-config/src/main/resources/config/openapi-validator.yaml:
--------------------------------------------------------------------------------
1 | # Default openapi-validator configuration
2 | # Enable request validation. Response validation is not done on the server but client.
3 | enabled: ${openapi-validator.enabled:true}
4 | # Log error message if validation error occurs
5 | logError: ${openapi-validator.logError:true}
6 | # By default, the json-schema-validator will return the error message using JSON_POINTER path type. If you want
7 | # to make sure that the error message is the same as the older version, you can set the legacyPathType to true.
8 | legacyPathType: ${openapi-validator.legacyPathType:false}
9 | # Skip body validation set to true if used in light-router, light-proxy and light-spring-boot.
10 | skipBodyValidation: ${openapi-validator.skipBodyValidation:false}
11 | # Enable response validation.
12 | validateResponse: ${openapi-validator.validateResponse:false}
13 | # When a field is set as nullable in the OpenAPI specification, the schema validator validates that it is nullable
14 | # however continues with validation against the nullable field
15 | #
16 | # If handleNullableField is set to true && incoming field is nullable && value is field: null --> succeed
17 | # If handleNullableField is set to false && incoming field is nullable && value is field: null --> it is up to the type
18 | # validator using the SchemaValidator to handle it.
19 | handleNullableField: ${openapi-validator.handleNullableField:true}
20 | # Define a list of path prefixes to skip the validation to ease the configuration for the
21 | # handler.yml so that users can define some endpoints without validation even through it uses
22 | # the default chain. This is particularly useful in the light-gateway use case as the same
23 | # instance might be shared with multiple consumers and providers with different validation
24 | # requirement. The format is a list of strings separated with commas or a JSON list in
25 | # values.yml definition from config server, or you can use yaml format in this file.
26 | skipPathPrefixes: ${openapi-validator.skipPathPrefixes:}
27 |
--------------------------------------------------------------------------------
/validator-config/src/main/resources/config/openapi-validator.yml:
--------------------------------------------------------------------------------
1 | # Default openapi-validator configuration
2 | ---
3 | # Enable request validation. Response validation is not done on the server but client.
4 | enabled: ${openapi-validator.enabled:true}
5 | # Log error message if validation error occurs
6 | logError: ${openapi-validator.logError:true}
7 | # By default, the json-schema-validator will return the error message using JSON_POINTER path type. If you want
8 | # to make sure that the error message is the same as the older version, you can set the legacyPathType to true.
9 | legacyPathType: ${openapi-validator.legacyPathType:false}
10 | # Skip body validation set to true if used in light-router, light-proxy and light-spring-boot.
11 | skipBodyValidation: ${openapi-validator.skipBodyValidation:false}
12 | # Enable response validation.
13 | validateResponse: ${openapi-validator.validateResponse:false}
14 | # When a field is set as nullable in the OpenAPI specification, the schema validator validates that it is nullable
15 | # however continues with validation against the nullable field
16 |
17 | # If handleNullableField is set to true && incoming field is nullable && value is field: null --> succeed
18 | # If handleNullableField is set to false && incoming field is nullable && value is field: null --> it is up to the type
19 | # validator using the SchemaValidator to handle it.
20 | handleNullableField: ${openapi-validator.handleNullableField:true}
21 |
22 | # Define a list of path prefixes to skip the validation to ease the configuration for the
23 | # handler.yml so that users can define some endpoints without validation even through it uses
24 | # the default chain. This is particularly useful in the light-gateway use case as the same
25 | # instance might be shared with multiple consumers and providers with different validation
26 | # requirement. The format is a list of strings separated with commas or a JSON list in
27 | # values.yml definition from config server, or you can use yaml format in this file.
28 | skipPathPrefixes: ${openapi-validator.skipPathPrefixes:}
29 |
--------------------------------------------------------------------------------