Showing
13 changed files
with
273 additions
and
45 deletions
... | ... | @@ -250,8 +250,8 @@ |
250 | 250 | <artifactId>grpc-stub</artifactId> |
251 | 251 | </dependency> |
252 | 252 | <dependency> |
253 | - <groupId>io.springfox</groupId> | |
254 | - <artifactId>springfox-swagger2</artifactId> | |
253 | + <groupId>org.thingsboard</groupId> | |
254 | + <artifactId>springfox-boot-starter</artifactId> | |
255 | 255 | </dependency> |
256 | 256 | <dependency> |
257 | 257 | <groupId>com.sun.winsw</groupId> |
... | ... | @@ -320,10 +320,6 @@ |
320 | 320 | <artifactId>delight-nashorn-sandbox</artifactId> |
321 | 321 | </dependency> |
322 | 322 | <dependency> |
323 | - <groupId>io.springfox.ui</groupId> | |
324 | - <artifactId>springfox-swagger-ui-rfc6570</artifactId> | |
325 | - </dependency> | |
326 | - <dependency> | |
327 | 323 | <groupId>org.passay</groupId> |
328 | 324 | <artifactId>passay</artifactId> |
329 | 325 | </dependency> | ... | ... |
... | ... | @@ -20,13 +20,11 @@ import org.springframework.boot.SpringBootConfiguration; |
20 | 20 | import org.springframework.context.annotation.ComponentScan; |
21 | 21 | import org.springframework.scheduling.annotation.EnableAsync; |
22 | 22 | import org.springframework.scheduling.annotation.EnableScheduling; |
23 | -import springfox.documentation.swagger2.annotations.EnableSwagger2; | |
24 | 23 | |
25 | 24 | import java.util.Arrays; |
26 | 25 | |
27 | 26 | @SpringBootConfiguration |
28 | 27 | @EnableAsync |
29 | -@EnableSwagger2 | |
30 | 28 | @EnableScheduling |
31 | 29 | @ComponentScan({"org.thingsboard.server"}) |
32 | 30 | public class ThingsboardServerApplication { | ... | ... |
... | ... | @@ -18,27 +18,60 @@ package org.thingsboard.server.config; |
18 | 18 | import com.fasterxml.classmate.ResolvedType; |
19 | 19 | import com.fasterxml.classmate.TypeResolver; |
20 | 20 | import com.fasterxml.jackson.databind.JsonNode; |
21 | -import com.google.common.base.Predicate; | |
21 | +import org.springframework.beans.factory.annotation.Autowired; | |
22 | 22 | import org.springframework.beans.factory.annotation.Value; |
23 | 23 | import org.springframework.context.annotation.Bean; |
24 | 24 | import org.springframework.context.annotation.Configuration; |
25 | +import org.springframework.core.annotation.Order; | |
26 | +import org.springframework.http.HttpMethod; | |
27 | +import org.springframework.http.MediaType; | |
25 | 28 | import org.thingsboard.server.common.data.security.Authority; |
29 | +import org.thingsboard.server.exception.ThingsboardErrorResponse; | |
30 | +import org.thingsboard.server.service.security.auth.rest.LoginRequest; | |
31 | +import org.thingsboard.server.service.security.auth.rest.LoginResponse; | |
26 | 32 | import springfox.documentation.builders.ApiInfoBuilder; |
27 | -import springfox.documentation.schema.AlternateTypeRule; | |
33 | +import springfox.documentation.builders.OperationBuilder; | |
34 | +import springfox.documentation.builders.RepresentationBuilder; | |
35 | +import springfox.documentation.builders.RequestParameterBuilder; | |
36 | +import springfox.documentation.builders.ResponseBuilder; | |
37 | +import springfox.documentation.service.ApiDescription; | |
28 | 38 | import springfox.documentation.service.ApiInfo; |
29 | -import springfox.documentation.service.ApiKey; | |
39 | +import springfox.documentation.service.ApiListing; | |
30 | 40 | import springfox.documentation.service.AuthorizationScope; |
31 | 41 | import springfox.documentation.service.Contact; |
42 | +import springfox.documentation.service.HttpLoginPasswordScheme; | |
43 | +import springfox.documentation.service.ParameterType; | |
44 | +import springfox.documentation.service.Response; | |
32 | 45 | import springfox.documentation.service.SecurityReference; |
46 | +import springfox.documentation.service.SecurityScheme; | |
47 | +import springfox.documentation.service.Tag; | |
33 | 48 | import springfox.documentation.spi.DocumentationType; |
49 | +import springfox.documentation.spi.service.ApiListingBuilderPlugin; | |
50 | +import springfox.documentation.spi.service.ApiListingScannerPlugin; | |
51 | +import springfox.documentation.spi.service.contexts.ApiListingContext; | |
52 | +import springfox.documentation.spi.service.contexts.DocumentationContext; | |
53 | +import springfox.documentation.spi.service.contexts.OperationContext; | |
34 | 54 | import springfox.documentation.spi.service.contexts.SecurityContext; |
35 | 55 | import springfox.documentation.spring.web.plugins.Docket; |
56 | +import springfox.documentation.spring.web.readers.operation.CachingOperationNameGenerator; | |
57 | +import springfox.documentation.swagger.common.SwaggerPluginSupport; | |
58 | +import springfox.documentation.swagger.web.DocExpansion; | |
59 | +import springfox.documentation.swagger.web.ModelRendering; | |
60 | +import springfox.documentation.swagger.web.OperationsSorter; | |
61 | +import springfox.documentation.swagger.web.UiConfiguration; | |
62 | +import springfox.documentation.swagger.web.UiConfigurationBuilder; | |
36 | 63 | |
64 | +import java.util.ArrayList; | |
65 | +import java.util.Collection; | |
66 | +import java.util.Collections; | |
37 | 67 | import java.util.List; |
68 | +import java.util.Set; | |
69 | +import java.util.function.Consumer; | |
70 | +import java.util.function.Predicate; | |
38 | 71 | |
39 | -import static com.google.common.base.Predicates.and; | |
40 | -import static com.google.common.base.Predicates.not; | |
41 | 72 | import static com.google.common.collect.Lists.newArrayList; |
73 | +import static java.util.function.Predicate.not; | |
74 | +import static springfox.documentation.builders.PathSelectors.any; | |
42 | 75 | import static springfox.documentation.builders.PathSelectors.regex; |
43 | 76 | |
44 | 77 | @Configuration |
... | ... | @@ -67,6 +100,9 @@ public class SwaggerConfiguration { |
67 | 100 | @Value("${swagger.version}") |
68 | 101 | private String version; |
69 | 102 | |
103 | + @Autowired | |
104 | + private CachingOperationNameGenerator operationNames; | |
105 | + | |
70 | 106 | @Bean |
71 | 107 | public Docket thingsboardApi() { |
72 | 108 | TypeResolver typeResolver = new TypeResolver(); |
... | ... | @@ -77,29 +113,110 @@ public class SwaggerConfiguration { |
77 | 113 | typeResolver.resolve( |
78 | 114 | String.class); |
79 | 115 | |
80 | - return new Docket(DocumentationType.SWAGGER_2) | |
116 | + return new Docket(DocumentationType.OAS_30) | |
81 | 117 | .groupName("thingsboard") |
82 | 118 | .apiInfo(apiInfo()) |
83 | - .alternateTypeRules( | |
119 | + .additionalModels( | |
120 | + typeResolver.resolve(ThingsboardErrorResponse.class), | |
121 | + typeResolver.resolve(LoginRequest.class), | |
122 | + typeResolver.resolve(LoginResponse.class) | |
123 | + ) | |
124 | + /* .alternateTypeRules( | |
84 | 125 | new AlternateTypeRule( |
85 | 126 | jsonNodeType, |
86 | - stringType)) | |
127 | + stringType))*/ | |
87 | 128 | .select() |
88 | 129 | .paths(apiPaths()) |
130 | + .paths(any()) | |
89 | 131 | .build() |
90 | - .securitySchemes(newArrayList(jwtTokenKey())) | |
132 | + .globalResponses(HttpMethod.GET, | |
133 | + List.of( | |
134 | + new ResponseBuilder() | |
135 | + .code("401") | |
136 | + .description("Unauthorized") | |
137 | + .representation(MediaType.APPLICATION_JSON) | |
138 | + .apply(classRepresentation(ThingsboardErrorResponse.class, true)) | |
139 | + .build() | |
140 | + ) | |
141 | + ) | |
142 | + .securitySchemes(newArrayList(httpLogin())) | |
91 | 143 | .securityContexts(newArrayList(securityContext())) |
92 | 144 | .enableUrlTemplating(true); |
93 | 145 | } |
94 | 146 | |
95 | - private ApiKey jwtTokenKey() { | |
96 | - return new ApiKey("X-Authorization", "JWT token", "header"); | |
147 | + @Bean | |
148 | + @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER) | |
149 | + ApiListingScannerPlugin loginEndpointListingScanner() { | |
150 | + return new ApiListingScannerPlugin() { | |
151 | + @Override | |
152 | + public List<ApiDescription> apply(DocumentationContext context) { | |
153 | + return List.of(loginEndpointApiDescription()); | |
154 | + } | |
155 | + | |
156 | + @Override | |
157 | + public boolean supports(DocumentationType delimiter) { | |
158 | + return DocumentationType.SWAGGER_2.equals(delimiter) || DocumentationType.OAS_30.equals(delimiter); | |
159 | + } | |
160 | + }; | |
161 | + } | |
162 | + | |
163 | + @Bean | |
164 | + @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER) | |
165 | + ApiListingBuilderPlugin loginEndpointListingBuilder() { | |
166 | + return new ApiListingBuilderPlugin() { | |
167 | + @Override | |
168 | + public void apply(ApiListingContext apiListingContext) { | |
169 | + if (apiListingContext.getResourceGroup().getGroupName().equals("default")) { | |
170 | + ApiListing apiListing = apiListingContext.apiListingBuilder().build(); | |
171 | + if (apiListing.getResourcePath().equals("/api/auth/login")) { | |
172 | + apiListingContext.apiListingBuilder().tags(Set.of(new Tag("login-endpoint", "Login Endpoint"))); | |
173 | + apiListingContext.apiListingBuilder().description("Login Endpoint"); | |
174 | + } | |
175 | + } | |
176 | + } | |
177 | + | |
178 | + @Override | |
179 | + public boolean supports(DocumentationType delimiter) { | |
180 | + return DocumentationType.SWAGGER_2.equals(delimiter) || DocumentationType.OAS_30.equals(delimiter); | |
181 | + } | |
182 | + }; | |
183 | + } | |
184 | + | |
185 | + @Bean | |
186 | + UiConfiguration uiConfig() { | |
187 | + return UiConfigurationBuilder.builder() | |
188 | + .deepLinking(true) | |
189 | + .displayOperationId(false) | |
190 | + .defaultModelsExpandDepth(1) | |
191 | + .defaultModelExpandDepth(1) | |
192 | + .defaultModelRendering(ModelRendering.EXAMPLE) | |
193 | + .displayRequestDuration(false) | |
194 | + .docExpansion(DocExpansion.NONE) | |
195 | + .filter(false) | |
196 | + .maxDisplayedTags(null) | |
197 | + .operationsSorter(OperationsSorter.ALPHA) | |
198 | + .showExtensions(false) | |
199 | + .showCommonExtensions(false) | |
200 | + .supportedSubmitMethods(UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS) | |
201 | + .validatorUrl(null) | |
202 | + .syntaxHighlightActivate(true) | |
203 | + .syntaxHighlightTheme("agate") | |
204 | + .build(); | |
205 | + } | |
206 | + | |
207 | + private SecurityScheme httpLogin() { | |
208 | + return HttpLoginPasswordScheme | |
209 | + .X_AUTHORIZATION_BUILDER | |
210 | + .loginEndpoint("/api/auth/login") | |
211 | + .name("HTTP login form") | |
212 | + .description("Enter Username / Password") | |
213 | + .build(); | |
97 | 214 | } |
98 | 215 | |
99 | 216 | private SecurityContext securityContext() { |
100 | 217 | return SecurityContext.builder() |
101 | 218 | .securityReferences(defaultAuth()) |
102 | - .forPaths(securityPaths()) | |
219 | + .operationSelector(securityPathOperationSelector()) | |
103 | 220 | .build(); |
104 | 221 | } |
105 | 222 | |
... | ... | @@ -107,11 +224,8 @@ public class SwaggerConfiguration { |
107 | 224 | return regex(apiPathRegex); |
108 | 225 | } |
109 | 226 | |
110 | - private Predicate<String> securityPaths() { | |
111 | - return and( | |
112 | - regex(securityPathRegex), | |
113 | - not(regex(nonSecurityPathRegex)) | |
114 | - ); | |
227 | + private Predicate<OperationContext> securityPathOperationSelector() { | |
228 | + return new SecurityPathOperationSelector(securityPathRegex, nonSecurityPathRegex); | |
115 | 229 | } |
116 | 230 | |
117 | 231 | List<SecurityReference> defaultAuth() { |
... | ... | @@ -120,7 +234,7 @@ public class SwaggerConfiguration { |
120 | 234 | authorizationScopes[1] = new AuthorizationScope(Authority.TENANT_ADMIN.name(), "Tenant administrator"); |
121 | 235 | authorizationScopes[2] = new AuthorizationScope(Authority.CUSTOMER_USER.name(), "Customer"); |
122 | 236 | return newArrayList( |
123 | - new SecurityReference("X-Authorization", authorizationScopes)); | |
237 | + new SecurityReference("HTTP login form", authorizationScopes)); | |
124 | 238 | } |
125 | 239 | |
126 | 240 | private ApiInfo apiInfo() { |
... | ... | @@ -134,4 +248,75 @@ public class SwaggerConfiguration { |
134 | 248 | .build(); |
135 | 249 | } |
136 | 250 | |
251 | + private ApiDescription loginEndpointApiDescription() { | |
252 | + return new ApiDescription(null, "/api/auth/login", "Login method to get user JWT token data", "Login endpoint", Collections.singletonList( | |
253 | + new OperationBuilder(operationNames) | |
254 | + .summary("Login method to get user JWT token data") | |
255 | + .tags(Set.of("login-endpoint")) | |
256 | + .authorizations(new ArrayList<>()) | |
257 | + .position(0) | |
258 | + .codegenMethodNameStem("loginPost") | |
259 | + .method(HttpMethod.POST) | |
260 | + .notes("Login method to get user JWT token data.\n\nValue of the response **token** field can be used as JWT token value for authorization.") | |
261 | + .requestParameters( | |
262 | + List.of( | |
263 | + new RequestParameterBuilder() | |
264 | + .in(ParameterType.BODY) | |
265 | + .required(true) | |
266 | + .description("Login request") | |
267 | + .content(c -> | |
268 | + c.requestBody(true) | |
269 | + .representation(MediaType.APPLICATION_JSON) | |
270 | + .apply(classRepresentation(LoginRequest.class, false)) | |
271 | + ) | |
272 | + .build() | |
273 | + ) | |
274 | + ) | |
275 | + .responses(loginResponses()) | |
276 | + .build() | |
277 | + ), false); | |
278 | + } | |
279 | + | |
280 | + private Collection<Response> loginResponses() { | |
281 | + return List.of( | |
282 | + new ResponseBuilder() | |
283 | + .code("200") | |
284 | + .description("OK") | |
285 | + .representation(MediaType.APPLICATION_JSON) | |
286 | + .apply(classRepresentation(LoginResponse.class, true)). | |
287 | + build() | |
288 | + ); | |
289 | + } | |
290 | + | |
291 | + /** Helper methods **/ | |
292 | + | |
293 | + private Consumer<RepresentationBuilder> classRepresentation(Class clazz, boolean isResponse) { | |
294 | + return r -> r.model( | |
295 | + m -> | |
296 | + m.referenceModel(ref -> | |
297 | + ref.key(k -> | |
298 | + k.qualifiedModelName(q -> | |
299 | + q.namespace(clazz.getPackageName()) | |
300 | + .name(clazz.getSimpleName())).isResponse(isResponse))) | |
301 | + ); | |
302 | + } | |
303 | + | |
304 | + private static class SecurityPathOperationSelector implements Predicate<OperationContext> { | |
305 | + | |
306 | + private final Predicate<String> securityPathSelector; | |
307 | + | |
308 | + SecurityPathOperationSelector(String securityPathRegex, String nonSecurityPathRegex) { | |
309 | + this.securityPathSelector = regex(securityPathRegex).and( | |
310 | + not( | |
311 | + regex(nonSecurityPathRegex) | |
312 | + )); | |
313 | + } | |
314 | + | |
315 | + @Override | |
316 | + public boolean test(OperationContext operationContext) { | |
317 | + return this.securityPathSelector.test(operationContext.requestMappingPattern()); | |
318 | + } | |
319 | + } | |
320 | + | |
321 | + | |
137 | 322 | } | ... | ... |
... | ... | @@ -64,6 +64,7 @@ import java.util.List; |
64 | 64 | public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapter { |
65 | 65 | |
66 | 66 | public static final String JWT_TOKEN_HEADER_PARAM = "X-Authorization"; |
67 | + public static final String JWT_TOKEN_HEADER_PARAM_V2 = "Authorization"; | |
67 | 68 | public static final String JWT_TOKEN_QUERY_PARAM = "token"; |
68 | 69 | |
69 | 70 | public static final String WEBJARS_ENTRY_POINT = "/webjars/**"; | ... | ... |
... | ... | @@ -18,12 +18,20 @@ package org.thingsboard.server.config; |
18 | 18 | import org.springframework.stereotype.Controller; |
19 | 19 | import org.springframework.web.bind.annotation.RequestMapping; |
20 | 20 | |
21 | +import javax.servlet.http.HttpServletResponse; | |
22 | +import java.io.IOException; | |
23 | + | |
21 | 24 | @Controller |
22 | 25 | public class WebConfig { |
23 | 26 | |
24 | - @RequestMapping(value = {"/assets", "/assets/", "/{path:^(?!api$)(?!assets$)(?!static$)(?!webjars$)[^\\.]*}/**"}) | |
27 | + @RequestMapping(value = {"/assets", "/assets/", "/{path:^(?!api$)(?!assets$)(?!static$)(?!webjars$)(?!swagger-ui$)[^\\.]*}/**"}) | |
25 | 28 | public String redirect() { |
26 | 29 | return "forward:/index.html"; |
27 | 30 | } |
28 | 31 | |
32 | + @RequestMapping("/swagger-ui.html") | |
33 | + public void redirectSwagger(HttpServletResponse response) throws IOException { | |
34 | + response.sendRedirect("/swagger-ui/"); | |
35 | + } | |
36 | + | |
29 | 37 | } | ... | ... |
... | ... | @@ -44,6 +44,7 @@ public class ControllerConstants { |
44 | 44 | protected static final String OTA_PACKAGE_ID_PARAM_DESCRIPTION = "A string value representing the ota package id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; |
45 | 45 | protected static final String ENTITY_TYPE_PARAM_DESCRIPTION = "A string value representing the entity type. For example, 'DEVICE'"; |
46 | 46 | protected static final String RULE_CHAIN_ID_PARAM_DESCRIPTION = "A string value representing the rule chain id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; |
47 | + protected static final String RULE_NODE_ID_PARAM_DESCRIPTION = "A string value representing the rule node id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; | |
47 | 48 | protected static final String WIDGET_BUNDLE_ID_PARAM_DESCRIPTION = "A string value representing the widget bundle id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; |
48 | 49 | protected static final String WIDGET_TYPE_ID_PARAM_DESCRIPTION = "A string value representing the widget type id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; |
49 | 50 | protected static final String RESOURCE_ID_PARAM_DESCRIPTION = "A string value representing the resource id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; | ... | ... |
... | ... | @@ -95,6 +95,7 @@ import static org.thingsboard.server.controller.ControllerConstants.RULE_CHAIN_S |
95 | 95 | import static org.thingsboard.server.controller.ControllerConstants.RULE_CHAIN_TEXT_SEARCH_DESCRIPTION; |
96 | 96 | import static org.thingsboard.server.controller.ControllerConstants.RULE_CHAIN_TYPES_ALLOWABLE_VALUES; |
97 | 97 | import static org.thingsboard.server.controller.ControllerConstants.RULE_CHAIN_TYPE_DESCRIPTION; |
98 | +import static org.thingsboard.server.controller.ControllerConstants.RULE_NODE_ID_PARAM_DESCRIPTION; | |
98 | 99 | import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; |
99 | 100 | import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; |
100 | 101 | import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; |
... | ... | @@ -434,7 +435,7 @@ public class RuleChainController extends BaseController { |
434 | 435 | @RequestMapping(value = "/ruleNode/{ruleNodeId}/debugIn", method = RequestMethod.GET) |
435 | 436 | @ResponseBody |
436 | 437 | public JsonNode getLatestRuleNodeDebugInput( |
437 | - @ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION) | |
438 | + @ApiParam(value = RULE_NODE_ID_PARAM_DESCRIPTION) | |
438 | 439 | @PathVariable(RULE_NODE_ID) String strRuleNodeId) throws ThingsboardException { |
439 | 440 | checkParameter(RULE_NODE_ID, strRuleNodeId); |
440 | 441 | try { | ... | ... |
... | ... | @@ -79,7 +79,7 @@ public class WidgetsBundleController extends BaseController { |
79 | 79 | |
80 | 80 | @ApiOperation(value = "Create Or Update Widget Bundle (saveWidgetsBundle)", |
81 | 81 | notes = "Create or update the Widget Bundle. " + WIDGET_BUNDLE_DESCRIPTION + " " + |
82 | - "When creating the bundle, platform generates Widget Bundle Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " + | |
82 | + "When creating the bundle, platform generates Widget Bundle Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address)). " + | |
83 | 83 | "The newly created Widget Bundle Id will be present in the response. " + |
84 | 84 | "Specify existing Widget Bundle id to update the Widget Bundle. " + |
85 | 85 | "Referencing non-existing Widget Bundle Id will cause 'Not Found' error." + | ... | ... |
... | ... | @@ -30,7 +30,10 @@ public class JwtHeaderTokenExtractor implements TokenExtractor { |
30 | 30 | public String extract(HttpServletRequest request) { |
31 | 31 | String header = request.getHeader(ThingsboardSecurityConfiguration.JWT_TOKEN_HEADER_PARAM); |
32 | 32 | if (StringUtils.isBlank(header)) { |
33 | - throw new AuthenticationServiceException("Authorization header cannot be blank!"); | |
33 | + header = request.getHeader(ThingsboardSecurityConfiguration.JWT_TOKEN_HEADER_PARAM_V2); | |
34 | + if (StringUtils.isBlank(header)) { | |
35 | + throw new AuthenticationServiceException("Authorization header cannot be blank!"); | |
36 | + } | |
34 | 37 | } |
35 | 38 | |
36 | 39 | if (header.length() < HEADER_PREFIX.length()) { | ... | ... |
... | ... | @@ -17,9 +17,14 @@ package org.thingsboard.server.service.security.auth.rest; |
17 | 17 | |
18 | 18 | import com.fasterxml.jackson.annotation.JsonCreator; |
19 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; |
20 | +import io.swagger.annotations.ApiModel; | |
21 | +import io.swagger.annotations.ApiModelProperty; | |
20 | 22 | |
23 | +@ApiModel | |
21 | 24 | public class LoginRequest { |
25 | + | |
22 | 26 | private String username; |
27 | + | |
23 | 28 | private String password; |
24 | 29 | |
25 | 30 | @JsonCreator |
... | ... | @@ -28,10 +33,12 @@ public class LoginRequest { |
28 | 33 | this.password = password; |
29 | 34 | } |
30 | 35 | |
36 | + @ApiModelProperty(position = 1, required = true, value = "User email", example = "tenant@thingsboard.org") | |
31 | 37 | public String getUsername() { |
32 | 38 | return username; |
33 | 39 | } |
34 | 40 | |
41 | + @ApiModelProperty(position = 2, required = true, value = "User password", example = "tenant") | |
35 | 42 | public String getPassword() { |
36 | 43 | return password; |
37 | 44 | } | ... | ... |
application/src/main/java/org/thingsboard/server/service/security/auth/rest/LoginResponse.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
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 | +package org.thingsboard.server.service.security.auth.rest; | |
17 | + | |
18 | +import io.swagger.annotations.ApiModel; | |
19 | +import io.swagger.annotations.ApiModelProperty; | |
20 | +import lombok.Data; | |
21 | + | |
22 | +@ApiModel | |
23 | +@Data | |
24 | +public class LoginResponse { | |
25 | + | |
26 | + @ApiModelProperty(position = 1, required = true, value = "JWT token", | |
27 | + example = "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZW5hbnRAdGhpbmdzYm9hcmQub3JnIi...") | |
28 | + private String token; | |
29 | + | |
30 | + @ApiModelProperty(position = 2, required = true, value = "Refresh token", | |
31 | + example = "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZW5hbnRAdGhpbmdzYm9hcmQub3JnIi...") | |
32 | + private String refreshToken; | |
33 | + | |
34 | +} | ... | ... |
... | ... | @@ -845,9 +845,9 @@ edges: |
845 | 845 | persistToTelemetry: "${EDGES_PERSIST_STATE_TO_TELEMETRY:false}" |
846 | 846 | |
847 | 847 | swagger: |
848 | - api_path_regex: "${SWAGGER_API_PATH_REGEX:/api.*}" | |
849 | - security_path_regex: "${SWAGGER_SECURITY_PATH_REGEX:/api.*}" | |
850 | - non_security_path_regex: "${SWAGGER_NON_SECURITY_PATH_REGEX:/api/noauth.*}" | |
848 | + api_path_regex: "${SWAGGER_API_PATH_REGEX:/api/.*}" | |
849 | + security_path_regex: "${SWAGGER_SECURITY_PATH_REGEX:/api/.*}" | |
850 | + non_security_path_regex: "${SWAGGER_NON_SECURITY_PATH_REGEX:/api/(?:noauth|v1)/.*}" | |
851 | 851 | title: "${SWAGGER_TITLE:ThingsBoard REST API}" |
852 | 852 | description: "${SWAGGER_DESCRIPTION:For instructions how to authorize requests please visit <a href='http://thingsboard.io/docs/reference/rest-api/'>REST API documentation page</a>.}" |
853 | 853 | contact: | ... | ... |
... | ... | @@ -46,8 +46,8 @@ |
46 | 46 | <spring-data-redis.version>2.4.3</spring-data-redis.version> |
47 | 47 | <jedis.version>3.3.0</jedis.version> |
48 | 48 | <jjwt.version>0.7.0</jjwt.version> |
49 | - <slf4j.version>1.7.7</slf4j.version> | |
50 | - <logback.version>1.2.3</logback.version> | |
49 | + <slf4j.version>1.7.32</slf4j.version> | |
50 | + <logback.version>1.2.6</logback.version> | |
51 | 51 | <rat.version>0.10</rat.version> |
52 | 52 | <cassandra.version>4.10.0</cassandra.version> |
53 | 53 | <metrics.version>4.0.5</metrics.version> |
... | ... | @@ -83,9 +83,8 @@ |
83 | 83 | <rabbitmq.version>4.8.0</rabbitmq.version> |
84 | 84 | <surfire.version>2.19.1</surfire.version> |
85 | 85 | <jar-plugin.version>3.0.2</jar-plugin.version> |
86 | - <springfox-swagger.version>2.6.1</springfox-swagger.version> | |
87 | - <springfox-swagger-ui-rfc6570.version>1.0.0</springfox-swagger-ui-rfc6570.version> | |
88 | - <swagger-annotations.version>1.5.10</swagger-annotations.version> | |
86 | + <springfox-swagger.version>3.0.1</springfox-swagger.version> | |
87 | + <swagger-annotations.version>1.6.3</swagger-annotations.version> | |
89 | 88 | <spatial4j.version>0.7</spatial4j.version> |
90 | 89 | <jts.version>1.15.0</jts.version> |
91 | 90 | <bouncycastle.version>1.67</bouncycastle.version> |
... | ... | @@ -1620,8 +1619,8 @@ |
1620 | 1619 | <version>${curator.version}</version> |
1621 | 1620 | </dependency> |
1622 | 1621 | <dependency> |
1623 | - <groupId>io.springfox</groupId> | |
1624 | - <artifactId>springfox-swagger2</artifactId> | |
1622 | + <groupId>org.thingsboard</groupId> | |
1623 | + <artifactId>springfox-boot-starter</artifactId> | |
1625 | 1624 | <version>${springfox-swagger.version}</version> |
1626 | 1625 | </dependency> |
1627 | 1626 | <dependency> |
... | ... | @@ -1700,11 +1699,6 @@ |
1700 | 1699 | <version>${fst.version}</version> |
1701 | 1700 | </dependency> |
1702 | 1701 | <dependency> |
1703 | - <groupId>io.springfox.ui</groupId> | |
1704 | - <artifactId>springfox-swagger-ui-rfc6570</artifactId> | |
1705 | - <version>${springfox-swagger-ui-rfc6570.version}</version> | |
1706 | - </dependency> | |
1707 | - <dependency> | |
1708 | 1702 | <groupId>org.locationtech.spatial4j</groupId> |
1709 | 1703 | <artifactId>spatial4j</artifactId> |
1710 | 1704 | <version>${spatial4j.version}</version> | ... | ... |