...
|
...
|
@@ -15,9 +15,9 @@ |
15
|
15
|
*/
|
16
|
16
|
package org.thingsboard.server.controller;
|
17
|
17
|
|
18
|
|
-import com.fasterxml.jackson.databind.JsonNode;
|
19
|
|
-import com.fasterxml.jackson.databind.ObjectMapper;
|
20
|
18
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
|
19
|
+import io.swagger.annotations.ApiOperation;
|
|
20
|
+import io.swagger.annotations.ApiParam;
|
21
|
21
|
import lombok.Getter;
|
22
|
22
|
import lombok.RequiredArgsConstructor;
|
23
|
23
|
import org.springframework.beans.factory.annotation.Value;
|
...
|
...
|
@@ -32,7 +32,6 @@ import org.springframework.web.bind.annotation.RequestParam; |
32
|
32
|
import org.springframework.web.bind.annotation.ResponseBody;
|
33
|
33
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
34
|
34
|
import org.springframework.web.bind.annotation.RestController;
|
35
|
|
-import org.thingsboard.common.util.JacksonUtil;
|
36
|
35
|
import org.thingsboard.rule.engine.api.MailService;
|
37
|
36
|
import org.thingsboard.server.common.data.EntityType;
|
38
|
37
|
import org.thingsboard.server.common.data.User;
|
...
|
...
|
@@ -52,6 +51,7 @@ import org.thingsboard.server.common.data.security.event.UserAuthDataChangedEven |
52
|
51
|
import org.thingsboard.server.common.data.security.model.JwtToken;
|
53
|
52
|
import org.thingsboard.server.queue.util.TbCoreComponent;
|
54
|
53
|
import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository;
|
|
54
|
+import org.thingsboard.server.service.security.model.JwtTokenPair;
|
55
|
55
|
import org.thingsboard.server.service.security.model.SecurityUser;
|
56
|
56
|
import org.thingsboard.server.service.security.model.UserPrincipal;
|
57
|
57
|
import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
|
...
|
...
|
@@ -82,20 +82,27 @@ public class UserController extends BaseController { |
82
|
82
|
private final SystemSecurityService systemSecurityService;
|
83
|
83
|
private final ApplicationEventPublisher eventPublisher;
|
84
|
84
|
|
|
85
|
+ @ApiOperation(value = "Get User (getUserById)",
|
|
86
|
+ notes = "Fetch the User object based on the provided User Id. " +
|
|
87
|
+ "If the user has the authority of 'SYS_ADMIN', the server does not perform additional checks. " +
|
|
88
|
+ "If the user has the authority of 'TENANT_ADMIN', the server checks that the requested user is owned by the same tenant. " +
|
|
89
|
+ "If the user has the authority of 'CUSTOMER_USER', the server checks that the requested user is owned by the same customer.")
|
85
|
90
|
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
|
86
|
91
|
@RequestMapping(value = "/user/{userId}", method = RequestMethod.GET)
|
87
|
92
|
@ResponseBody
|
88
|
|
- public User getUserById(@PathVariable(USER_ID) String strUserId) throws ThingsboardException {
|
|
93
|
+ public User getUserById(
|
|
94
|
+ @ApiParam(value = USER_ID_PARAM_DESCRIPTION)
|
|
95
|
+ @PathVariable(USER_ID) String strUserId) throws ThingsboardException {
|
89
|
96
|
checkParameter(USER_ID, strUserId);
|
90
|
97
|
try {
|
91
|
98
|
UserId userId = new UserId(toUUID(strUserId));
|
92
|
99
|
User user = checkUserId(userId, Operation.READ);
|
93
|
|
- if(user.getAdditionalInfo().isObject()) {
|
|
100
|
+ if (user.getAdditionalInfo().isObject()) {
|
94
|
101
|
ObjectNode additionalInfo = (ObjectNode) user.getAdditionalInfo();
|
95
|
102
|
processDashboardIdFromAdditionalInfo(additionalInfo, DEFAULT_DASHBOARD);
|
96
|
103
|
processDashboardIdFromAdditionalInfo(additionalInfo, HOME_DASHBOARD);
|
97
|
104
|
UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId());
|
98
|
|
- if(userCredentials.isEnabled() && !additionalInfo.has("userCredentialsEnabled")) {
|
|
105
|
+ if (userCredentials.isEnabled() && !additionalInfo.has("userCredentialsEnabled")) {
|
99
|
106
|
additionalInfo.put("userCredentialsEnabled", true);
|
100
|
107
|
}
|
101
|
108
|
}
|
...
|
...
|
@@ -105,6 +112,10 @@ public class UserController extends BaseController { |
105
|
112
|
}
|
106
|
113
|
}
|
107
|
114
|
|
|
115
|
+ @ApiOperation(value = "Check Token Access Enabled (isUserTokenAccessEnabled)",
|
|
116
|
+ notes = "Checks that the system is configured to allow administrators to impersonate themself as other users. " +
|
|
117
|
+ "If the user who performs the request has the authority of 'SYS_ADMIN', it is possible to login as any tenant administrator. " +
|
|
118
|
+ "If the user who performs the request has the authority of 'TENANT_ADMIN', it is possible to login as any customer user. ")
|
108
|
119
|
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
|
109
|
120
|
@RequestMapping(value = "/user/tokenAccessEnabled", method = RequestMethod.GET)
|
110
|
121
|
@ResponseBody
|
...
|
...
|
@@ -112,10 +123,16 @@ public class UserController extends BaseController { |
112
|
123
|
return userTokenAccessEnabled;
|
113
|
124
|
}
|
114
|
125
|
|
|
126
|
+ @ApiOperation(value = "Get User Token (getUserToken)",
|
|
127
|
+ notes = "Returns the token of the User based on the provided User Id. " +
|
|
128
|
+ "If the user who performs the request has the authority of 'SYS_ADMIN', it is possible to get the token of any tenant administrator. " +
|
|
129
|
+ "If the user who performs the request has the authority of 'TENANT_ADMIN', it is possible to get the token of any customer user that belongs to the same tenant. ")
|
115
|
130
|
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
|
116
|
131
|
@RequestMapping(value = "/user/{userId}/token", method = RequestMethod.GET)
|
117
|
132
|
@ResponseBody
|
118
|
|
- public JsonNode getUserToken(@PathVariable(USER_ID) String strUserId) throws ThingsboardException {
|
|
133
|
+ public JwtTokenPair getUserToken(
|
|
134
|
+ @ApiParam(value = USER_ID_PARAM_DESCRIPTION)
|
|
135
|
+ @PathVariable(USER_ID) String strUserId) throws ThingsboardException {
|
119
|
136
|
checkParameter(USER_ID, strUserId);
|
120
|
137
|
try {
|
121
|
138
|
if (!userTokenAccessEnabled) {
|
...
|
...
|
@@ -130,22 +147,26 @@ public class UserController extends BaseController { |
130
|
147
|
SecurityUser securityUser = new SecurityUser(user, credentials.isEnabled(), principal);
|
131
|
148
|
JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser);
|
132
|
149
|
JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser);
|
133
|
|
- ObjectMapper objectMapper = new ObjectMapper();
|
134
|
|
- ObjectNode tokenObject = objectMapper.createObjectNode();
|
135
|
|
- tokenObject.put("token", accessToken.getToken());
|
136
|
|
- tokenObject.put("refreshToken", refreshToken.getToken());
|
137
|
|
- return tokenObject;
|
|
150
|
+ return new JwtTokenPair(accessToken.getToken(), refreshToken.getToken());
|
138
|
151
|
} catch (Exception e) {
|
139
|
152
|
throw handleException(e);
|
140
|
153
|
}
|
141
|
154
|
}
|
142
|
155
|
|
|
156
|
+ @ApiOperation(value = "Save Or update User (saveUser)",
|
|
157
|
+ notes = "Create or update the User. When creating user, platform generates User Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " +
|
|
158
|
+ "The newly created User Id will be present in the response. " +
|
|
159
|
+ "Specify existing User Id to update the device. " +
|
|
160
|
+ "Referencing non-existing User Id will cause 'Not Found' error." +
|
|
161
|
+ "\n\nDevice email is unique for entire platform setup.")
|
143
|
162
|
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
|
144
|
163
|
@RequestMapping(value = "/user", method = RequestMethod.POST)
|
145
|
164
|
@ResponseBody
|
146
|
|
- public User saveUser(@RequestBody User user,
|
147
|
|
- @RequestParam(required = false, defaultValue = "true") boolean sendActivationMail,
|
148
|
|
- HttpServletRequest request) throws ThingsboardException {
|
|
165
|
+ public User saveUser(
|
|
166
|
+ @ApiParam(value = "A JSON value representing the User.", required = true)
|
|
167
|
+ @RequestBody User user,
|
|
168
|
+ @ApiParam(value = "Send activation email (or use activation link)", defaultValue = "true")
|
|
169
|
+ @RequestParam(required = false, defaultValue = "true") boolean sendActivationMail, HttpServletRequest request) throws ThingsboardException {
|
149
|
170
|
try {
|
150
|
171
|
|
151
|
172
|
if (Authority.TENANT_ADMIN.equals(getCurrentUser().getAuthority())) {
|
...
|
...
|
@@ -188,10 +209,13 @@ public class UserController extends BaseController { |
188
|
209
|
}
|
189
|
210
|
}
|
190
|
211
|
|
|
212
|
+ @ApiOperation(value = "Send or re-send the activation email",
|
|
213
|
+ notes = "Force send the activation email to the user. Useful to resend the email if user has accidentally deleted it. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
|
191
|
214
|
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
|
192
|
215
|
@RequestMapping(value = "/user/sendActivationMail", method = RequestMethod.POST)
|
193
|
216
|
@ResponseStatus(value = HttpStatus.OK)
|
194
|
217
|
public void sendActivationEmail(
|
|
218
|
+ @ApiParam(value = "Email of the user", required = true)
|
195
|
219
|
@RequestParam(value = "email") String email,
|
196
|
220
|
HttpServletRequest request) throws ThingsboardException {
|
197
|
221
|
try {
|
...
|
...
|
@@ -214,10 +238,14 @@ public class UserController extends BaseController { |
214
|
238
|
}
|
215
|
239
|
}
|
216
|
240
|
|
|
241
|
+ @ApiOperation(value = "Get the activation link (getActivationLink)",
|
|
242
|
+ notes = "Get the activation link for the user. " +
|
|
243
|
+ "The base url for activation link is configurable in the general settings of system administrator. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
|
217
|
244
|
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
|
218
|
245
|
@RequestMapping(value = "/user/{userId}/activationLink", method = RequestMethod.GET, produces = "text/plain")
|
219
|
246
|
@ResponseBody
|
220
|
247
|
public String getActivationLink(
|
|
248
|
+ @ApiParam(value = USER_ID_PARAM_DESCRIPTION)
|
221
|
249
|
@PathVariable(USER_ID) String strUserId,
|
222
|
250
|
HttpServletRequest request) throws ThingsboardException {
|
223
|
251
|
checkParameter(USER_ID, strUserId);
|
...
|
...
|
@@ -239,10 +267,15 @@ public class UserController extends BaseController { |
239
|
267
|
}
|
240
|
268
|
}
|
241
|
269
|
|
|
270
|
+ @ApiOperation(value = "Delete User (deleteUser)",
|
|
271
|
+ notes = "Deletes the User, it's credentials and all the relations (from and to the User). " +
|
|
272
|
+ "Referencing non-existing User Id will cause an error. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
|
242
|
273
|
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
|
243
|
274
|
@RequestMapping(value = "/user/{userId}", method = RequestMethod.DELETE)
|
244
|
275
|
@ResponseStatus(value = HttpStatus.OK)
|
245
|
|
- public void deleteUser(@PathVariable(USER_ID) String strUserId) throws ThingsboardException {
|
|
276
|
+ public void deleteUser(
|
|
277
|
+ @ApiParam(value = USER_ID_PARAM_DESCRIPTION)
|
|
278
|
+ @PathVariable(USER_ID) String strUserId) throws ThingsboardException {
|
246
|
279
|
checkParameter(USER_ID, strUserId);
|
247
|
280
|
try {
|
248
|
281
|
UserId userId = new UserId(toUUID(strUserId));
|
...
|
...
|
@@ -267,14 +300,22 @@ public class UserController extends BaseController { |
267
|
300
|
}
|
268
|
301
|
}
|
269
|
302
|
|
|
303
|
+ @ApiOperation(value = "Get Users (getUsers)",
|
|
304
|
+ notes = "Returns a page of users owned by tenant or customer. The scope depends on authority of the user that performs the request." +
|
|
305
|
+ PAGE_DATA_PARAMETERS + TENANT_OR_USER_AUTHORITY_PARAGRAPH)
|
270
|
306
|
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
|
271
|
307
|
@RequestMapping(value = "/users", params = {"pageSize", "page"}, method = RequestMethod.GET)
|
272
|
308
|
@ResponseBody
|
273
|
309
|
public PageData<User> getUsers(
|
|
310
|
+ @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
|
274
|
311
|
@RequestParam int pageSize,
|
|
312
|
+ @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
|
275
|
313
|
@RequestParam int page,
|
|
314
|
+ @ApiParam(value = USER_TEXT_SEARCH_DESCRIPTION)
|
276
|
315
|
@RequestParam(required = false) String textSearch,
|
|
316
|
+ @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = USER_SORT_PROPERTY_ALLOWABLE_VALUES)
|
277
|
317
|
@RequestParam(required = false) String sortProperty,
|
|
318
|
+ @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
|
278
|
319
|
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
|
279
|
320
|
try {
|
280
|
321
|
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
|
...
|
...
|
@@ -289,15 +330,23 @@ public class UserController extends BaseController { |
289
|
330
|
}
|
290
|
331
|
}
|
291
|
332
|
|
|
333
|
+ @ApiOperation(value = "Get Tenant Users (getTenantAdmins)",
|
|
334
|
+ notes = "Returns a page of users owned by tenant. " + PAGE_DATA_PARAMETERS + SYSTEM_AUTHORITY_PARAGRAPH)
|
292
|
335
|
@PreAuthorize("hasAuthority('SYS_ADMIN')")
|
293
|
336
|
@RequestMapping(value = "/tenant/{tenantId}/users", params = {"pageSize", "page"}, method = RequestMethod.GET)
|
294
|
337
|
@ResponseBody
|
295
|
338
|
public PageData<User> getTenantAdmins(
|
296
|
|
- @PathVariable("tenantId") String strTenantId,
|
|
339
|
+ @ApiParam(value = TENANT_ID_PARAM_DESCRIPTION, required = true)
|
|
340
|
+ @PathVariable(TENANT_ID) String strTenantId,
|
|
341
|
+ @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
|
297
|
342
|
@RequestParam int pageSize,
|
|
343
|
+ @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
|
298
|
344
|
@RequestParam int page,
|
|
345
|
+ @ApiParam(value = USER_TEXT_SEARCH_DESCRIPTION)
|
299
|
346
|
@RequestParam(required = false) String textSearch,
|
|
347
|
+ @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = USER_SORT_PROPERTY_ALLOWABLE_VALUES)
|
300
|
348
|
@RequestParam(required = false) String sortProperty,
|
|
349
|
+ @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
|
301
|
350
|
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
|
302
|
351
|
checkParameter("tenantId", strTenantId);
|
303
|
352
|
try {
|
...
|
...
|
@@ -309,15 +358,23 @@ public class UserController extends BaseController { |
309
|
358
|
}
|
310
|
359
|
}
|
311
|
360
|
|
|
361
|
+ @ApiOperation(value = "Get Customer Users (getCustomerUsers)",
|
|
362
|
+ notes = "Returns a page of users owned by customer. " + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
|
312
|
363
|
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
|
313
|
364
|
@RequestMapping(value = "/customer/{customerId}/users", params = {"pageSize", "page"}, method = RequestMethod.GET)
|
314
|
365
|
@ResponseBody
|
315
|
366
|
public PageData<User> getCustomerUsers(
|
316
|
|
- @PathVariable("customerId") String strCustomerId,
|
|
367
|
+ @ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
|
|
368
|
+ @PathVariable(CUSTOMER_ID) String strCustomerId,
|
|
369
|
+ @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
|
317
|
370
|
@RequestParam int pageSize,
|
|
371
|
+ @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
|
318
|
372
|
@RequestParam int page,
|
|
373
|
+ @ApiParam(value = USER_TEXT_SEARCH_DESCRIPTION)
|
319
|
374
|
@RequestParam(required = false) String textSearch,
|
|
375
|
+ @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = USER_SORT_PROPERTY_ALLOWABLE_VALUES)
|
320
|
376
|
@RequestParam(required = false) String sortProperty,
|
|
377
|
+ @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
|
321
|
378
|
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
|
322
|
379
|
checkParameter("customerId", strCustomerId);
|
323
|
380
|
try {
|
...
|
...
|
@@ -331,11 +388,16 @@ public class UserController extends BaseController { |
331
|
388
|
}
|
332
|
389
|
}
|
333
|
390
|
|
|
391
|
+ @ApiOperation(value = "Enable/Disable User credentials (setUserCredentialsEnabled)",
|
|
392
|
+ notes = "Enables or Disables user credentials. Useful when you would like to block user account without deleting it. " + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
|
334
|
393
|
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
|
335
|
394
|
@RequestMapping(value = "/user/{userId}/userCredentialsEnabled", method = RequestMethod.POST)
|
336
|
395
|
@ResponseBody
|
337
|
|
- public void setUserCredentialsEnabled(@PathVariable(USER_ID) String strUserId,
|
338
|
|
- @RequestParam(required = false, defaultValue = "true") boolean userCredentialsEnabled) throws ThingsboardException {
|
|
396
|
+ public void setUserCredentialsEnabled(
|
|
397
|
+ @ApiParam(value = USER_ID_PARAM_DESCRIPTION)
|
|
398
|
+ @PathVariable(USER_ID) String strUserId,
|
|
399
|
+ @ApiParam(value = "Disable (\"true\") or enable (\"false\") the credentials.", defaultValue = "true")
|
|
400
|
+ @RequestParam(required = false, defaultValue = "true") boolean userCredentialsEnabled) throws ThingsboardException {
|
339
|
401
|
checkParameter(USER_ID, strUserId);
|
340
|
402
|
try {
|
341
|
403
|
UserId userId = new UserId(toUUID(strUserId));
|
...
|
...
|
|