/** * Copyright © 2016-2017 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.thingsboard.server.controller; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import org.apache.commons.lang3.RandomStringUtils; import org.junit.Assert; import org.junit.Test; import org.springframework.http.HttpHeaders; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.service.mail.TestMailService; import java.util.ArrayList; import java.util.Collections; import java.util.List; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; public class UserControllerTest extends AbstractControllerTest { private IdComparator<User> idComparator = new IdComparator<>(); @Test public void testSaveUser() throws Exception { loginSysAdmin(); Tenant tenant = new Tenant(); tenant.setTitle("My tenant"); Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); Assert.assertNotNull(savedTenant); String email = "tenant2@thingsboard.org"; User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); user.setTenantId(savedTenant.getId()); user.setEmail(email); user.setFirstName("Joe"); user.setLastName("Downs"); User savedUser = doPost("/api/user", user, User.class); Assert.assertNotNull(savedUser); Assert.assertNotNull(savedUser.getId()); Assert.assertTrue(savedUser.getCreatedTime() > 0); Assert.assertEquals(user.getEmail(), savedUser.getEmail()); User foundUser = doGet("/api/user/"+savedUser.getId().getId().toString(), User.class); Assert.assertEquals(foundUser, savedUser); logout(); doGet("/api/noauth/activate?activateToken={activateToken}", TestMailService.currentActivateToken) .andExpect(status().isPermanentRedirect()) .andExpect(header().string(HttpHeaders.LOCATION, "/login/createPassword?activateToken=" + TestMailService.currentActivateToken)); JsonNode tokenInfo = readResponse(doPost("/api/noauth/activate", "activateToken", TestMailService.currentActivateToken, "password", "testPassword").andExpect(status().isOk()), JsonNode.class); validateAndSetJwtToken(tokenInfo, email); doGet("/api/auth/user") .andExpect(status().isOk()) .andExpect(jsonPath("$.authority",is(Authority.TENANT_ADMIN.name()))) .andExpect(jsonPath("$.email",is(email))); logout(); login(email, "testPassword"); doGet("/api/auth/user") .andExpect(status().isOk()) .andExpect(jsonPath("$.authority",is(Authority.TENANT_ADMIN.name()))) .andExpect(jsonPath("$.email",is(email))); loginSysAdmin(); doDelete("/api/user/"+savedUser.getId().getId().toString()) .andExpect(status().isOk()); doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) .andExpect(status().isOk()); } @Test public void testResetPassword() throws Exception { loginSysAdmin(); Tenant tenant = new Tenant(); tenant.setTitle("My tenant"); Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); Assert.assertNotNull(savedTenant); String email = "tenant2@thingsboard.org"; User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); user.setTenantId(savedTenant.getId()); user.setEmail(email); user.setFirstName("Joe"); user.setLastName("Downs"); User savedUser = createUserAndLogin(user, "testPassword1"); logout(); doPost("/api/noauth/resetPasswordByEmail", "email", email) .andExpect(status().isOk()); doGet("/api/noauth/resetPassword?resetToken={resetToken}", TestMailService.currentResetPasswordToken) .andExpect(status().isPermanentRedirect()) .andExpect(header().string(HttpHeaders.LOCATION, "/login/resetPassword?resetToken=" + TestMailService.currentResetPasswordToken)); JsonNode tokenInfo = readResponse(doPost("/api/noauth/resetPassword", "resetToken", TestMailService.currentResetPasswordToken, "password", "testPassword2").andExpect(status().isOk()), JsonNode.class); validateAndSetJwtToken(tokenInfo, email); doGet("/api/auth/user") .andExpect(status().isOk()) .andExpect(jsonPath("$.authority",is(Authority.TENANT_ADMIN.name()))) .andExpect(jsonPath("$.email",is(email))); logout(); login(email, "testPassword2"); doGet("/api/auth/user") .andExpect(status().isOk()) .andExpect(jsonPath("$.authority",is(Authority.TENANT_ADMIN.name()))) .andExpect(jsonPath("$.email",is(email))); loginSysAdmin(); doDelete("/api/user/"+savedUser.getId().getId().toString()) .andExpect(status().isOk()); doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) .andExpect(status().isOk()); } @Test public void testFindUserById() throws Exception { loginSysAdmin(); Tenant tenant = new Tenant(); tenant.setTitle("My tenant"); Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); Assert.assertNotNull(savedTenant); String email = "tenant2@thingsboard.org"; User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); user.setTenantId(savedTenant.getId()); user.setEmail(email); user.setFirstName("Joe"); user.setLastName("Downs"); User savedUser = doPost("/api/user", user, User.class); User foundUser = doGet("/api/user/"+savedUser.getId().getId().toString(), User.class); Assert.assertNotNull(foundUser); Assert.assertEquals(savedUser, foundUser); doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) .andExpect(status().isOk()); } @Test public void testSaveUserWithSameEmail() throws Exception { loginSysAdmin(); Tenant tenant = new Tenant(); tenant.setTitle("My tenant"); Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); Assert.assertNotNull(savedTenant); String email = "tenant@thingsboard.org"; User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); user.setTenantId(savedTenant.getId()); user.setEmail(email); user.setFirstName("Joe"); user.setLastName("Downs"); doPost("/api/user", user) .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString("User with email '" + email + "' already present in database"))); doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) .andExpect(status().isOk()); } @Test public void testSaveUserWithInvalidEmail() throws Exception { loginSysAdmin(); Tenant tenant = new Tenant(); tenant.setTitle("My tenant"); Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); Assert.assertNotNull(savedTenant); String email = "tenant_thingsboard.org"; User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); user.setTenantId(savedTenant.getId()); user.setEmail(email); user.setFirstName("Joe"); user.setLastName("Downs"); doPost("/api/user", user) .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString("Invalid email address format '" + email + "'"))); doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) .andExpect(status().isOk()); } @Test public void testSaveUserWithEmptyEmail() throws Exception { loginSysAdmin(); Tenant tenant = new Tenant(); tenant.setTitle("My tenant"); Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); Assert.assertNotNull(savedTenant); User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); user.setTenantId(savedTenant.getId()); user.setFirstName("Joe"); user.setLastName("Downs"); doPost("/api/user", user) .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString("User email should be specified"))); doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) .andExpect(status().isOk()); } @Test public void testSaveUserWithoutTenant() throws Exception { loginSysAdmin(); User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); user.setEmail("tenant2@thingsboard.org"); user.setFirstName("Joe"); user.setLastName("Downs"); doPost("/api/user", user) .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString("Tenant administrator should be assigned to tenant"))); } @Test public void testDeleteUser() throws Exception { loginSysAdmin(); Tenant tenant = new Tenant(); tenant.setTitle("My tenant"); Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); Assert.assertNotNull(savedTenant); String email = "tenant2@thingsboard.org"; User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); user.setTenantId(savedTenant.getId()); user.setEmail(email); user.setFirstName("Joe"); user.setLastName("Downs"); User savedUser = doPost("/api/user", user, User.class); User foundUser = doGet("/api/user/"+savedUser.getId().getId().toString(), User.class); Assert.assertNotNull(foundUser); doDelete("/api/user/"+savedUser.getId().getId().toString()) .andExpect(status().isOk()); doGet("/api/user/"+savedUser.getId().getId().toString()) .andExpect(status().isNotFound()); doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) .andExpect(status().isOk()); } @Test public void testFindTenantAdmins() throws Exception { loginSysAdmin(); Tenant tenant = new Tenant(); tenant.setTitle("My tenant"); Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); Assert.assertNotNull(savedTenant); TenantId tenantId = savedTenant.getId(); List<User> tenantAdmins = new ArrayList<>(); for (int i=0;i<64;i++) { User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); user.setTenantId(tenantId); user.setEmail("testTenant" + i + "@thingsboard.org"); tenantAdmins.add(doPost("/api/user", user, User.class)); } List<User> loadedTenantAdmins = new ArrayList<>(); TextPageLink pageLink = new TextPageLink(33); TextPageData<User> pageData = null; do { pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", new TypeReference<TextPageData<User>>(){}, pageLink); loadedTenantAdmins.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageData.getNextPageLink(); } } while (pageData.hasNext()); Collections.sort(tenantAdmins, idComparator); Collections.sort(loadedTenantAdmins, idComparator); Assert.assertEquals(tenantAdmins, loadedTenantAdmins); doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) .andExpect(status().isOk()); pageLink = new TextPageLink(33); pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", new TypeReference<TextPageData<User>>(){}, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertTrue(pageData.getData().isEmpty()); } @Test public void testFindTenantAdminsByEmail() throws Exception { loginSysAdmin(); Tenant tenant = new Tenant(); tenant.setTitle("My tenant"); Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); Assert.assertNotNull(savedTenant); TenantId tenantId = savedTenant.getId(); String email1 = "testEmail1"; List<User> tenantAdminsEmail1 = new ArrayList<>(); for (int i=0;i<124;i++) { User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); user.setTenantId(tenantId); String suffix = RandomStringUtils.randomAlphanumeric((int)(5 + Math.random()*10)); String email = email1+suffix+ "@thingsboard.org"; email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase(); user.setEmail(email); tenantAdminsEmail1.add(doPost("/api/user", user, User.class)); } String email2 = "testEmail2"; List<User> tenantAdminsEmail2 = new ArrayList<>(); for (int i=0;i<112;i++) { User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); user.setTenantId(tenantId); String suffix = RandomStringUtils.randomAlphanumeric((int)(5 + Math.random()*10)); String email = email2+suffix+ "@thingsboard.org"; email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase(); user.setEmail(email); tenantAdminsEmail2.add(doPost("/api/user", user, User.class)); } List<User> loadedTenantAdminsEmail1 = new ArrayList<>(); TextPageLink pageLink = new TextPageLink(33, email1); TextPageData<User> pageData = null; do { pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", new TypeReference<TextPageData<User>>(){}, pageLink); loadedTenantAdminsEmail1.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageData.getNextPageLink(); } } while (pageData.hasNext()); Collections.sort(tenantAdminsEmail1, idComparator); Collections.sort(loadedTenantAdminsEmail1, idComparator); Assert.assertEquals(tenantAdminsEmail1, loadedTenantAdminsEmail1); List<User> loadedTenantAdminsEmail2 = new ArrayList<>(); pageLink = new TextPageLink(16, email2); do { pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", new TypeReference<TextPageData<User>>(){}, pageLink); loadedTenantAdminsEmail2.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageData.getNextPageLink(); } } while (pageData.hasNext()); Collections.sort(tenantAdminsEmail2, idComparator); Collections.sort(loadedTenantAdminsEmail2, idComparator); Assert.assertEquals(tenantAdminsEmail2, loadedTenantAdminsEmail2); for (User user : loadedTenantAdminsEmail1) { doDelete("/api/user/"+user.getId().getId().toString()) .andExpect(status().isOk()); } pageLink = new TextPageLink(4, email1); pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", new TypeReference<TextPageData<User>>(){}, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); for (User user : loadedTenantAdminsEmail2) { doDelete("/api/user/"+user.getId().getId().toString()) .andExpect(status().isOk()); } pageLink = new TextPageLink(4, email2); pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", new TypeReference<TextPageData<User>>(){}, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) .andExpect(status().isOk()); } @Test public void testFindCustomerUsers() throws Exception { loginSysAdmin(); Tenant tenant = new Tenant(); tenant.setTitle("My tenant"); Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); Assert.assertNotNull(savedTenant); TenantId tenantId = savedTenant.getId(); User tenantAdmin = new User(); tenantAdmin.setAuthority(Authority.TENANT_ADMIN); tenantAdmin.setTenantId(tenantId); tenantAdmin.setEmail("tenant2@thingsboard.org"); tenantAdmin.setFirstName("Joe"); tenantAdmin.setLastName("Downs"); tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); Customer customer = new Customer(); customer.setTitle("My customer"); Customer savedCustomer = doPost("/api/customer", customer, Customer.class); CustomerId customerId = savedCustomer.getId(); List<User> customerUsers = new ArrayList<>(); for (int i=0;i<56;i++) { User user = new User(); user.setAuthority(Authority.CUSTOMER_USER); user.setCustomerId(customerId); user.setEmail("testCustomer" + i + "@thingsboard.org"); customerUsers.add(doPost("/api/user", user, User.class)); } List<User> loadedCustomerUsers = new ArrayList<>(); TextPageLink pageLink = new TextPageLink(33); TextPageData<User> pageData = null; do { pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", new TypeReference<TextPageData<User>>(){}, pageLink); loadedCustomerUsers.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageData.getNextPageLink(); } } while (pageData.hasNext()); Collections.sort(customerUsers, idComparator); Collections.sort(loadedCustomerUsers, idComparator); Assert.assertEquals(customerUsers, loadedCustomerUsers); doDelete("/api/customer/"+customerId.getId().toString()) .andExpect(status().isOk()); loginSysAdmin(); doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) .andExpect(status().isOk()); } @Test public void testFindCustomerUsersByEmail() throws Exception { loginSysAdmin(); Tenant tenant = new Tenant(); tenant.setTitle("My tenant"); Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); Assert.assertNotNull(savedTenant); TenantId tenantId = savedTenant.getId(); User tenantAdmin = new User(); tenantAdmin.setAuthority(Authority.TENANT_ADMIN); tenantAdmin.setTenantId(tenantId); tenantAdmin.setEmail("tenant2@thingsboard.org"); tenantAdmin.setFirstName("Joe"); tenantAdmin.setLastName("Downs"); tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); Customer customer = new Customer(); customer.setTitle("My customer"); Customer savedCustomer = doPost("/api/customer", customer, Customer.class); CustomerId customerId = savedCustomer.getId(); String email1 = "testEmail1"; List<User> customerUsersEmail1 = new ArrayList<>(); for (int i=0;i<74;i++) { User user = new User(); user.setAuthority(Authority.CUSTOMER_USER); user.setCustomerId(customerId); String suffix = RandomStringUtils.randomAlphanumeric((int)(5 + Math.random()*10)); String email = email1+suffix+ "@thingsboard.org"; email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase(); user.setEmail(email); customerUsersEmail1.add(doPost("/api/user", user, User.class)); } String email2 = "testEmail2"; List<User> customerUsersEmail2 = new ArrayList<>(); for (int i=0;i<92;i++) { User user = new User(); user.setAuthority(Authority.CUSTOMER_USER); user.setCustomerId(customerId); String suffix = RandomStringUtils.randomAlphanumeric((int)(5 + Math.random()*10)); String email = email2+suffix+ "@thingsboard.org"; email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase(); user.setEmail(email); customerUsersEmail2.add(doPost("/api/user", user, User.class)); } List<User> loadedCustomerUsersEmail1 = new ArrayList<>(); TextPageLink pageLink = new TextPageLink(33, email1); TextPageData<User> pageData = null; do { pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", new TypeReference<TextPageData<User>>(){}, pageLink); loadedCustomerUsersEmail1.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageData.getNextPageLink(); } } while (pageData.hasNext()); Collections.sort(customerUsersEmail1, idComparator); Collections.sort(loadedCustomerUsersEmail1, idComparator); Assert.assertEquals(customerUsersEmail1, loadedCustomerUsersEmail1); List<User> loadedCustomerUsersEmail2 = new ArrayList<>(); pageLink = new TextPageLink(16, email2); do { pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", new TypeReference<TextPageData<User>>(){}, pageLink); loadedCustomerUsersEmail2.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageData.getNextPageLink(); } } while (pageData.hasNext()); Collections.sort(customerUsersEmail2, idComparator); Collections.sort(loadedCustomerUsersEmail2, idComparator); Assert.assertEquals(customerUsersEmail2, loadedCustomerUsersEmail2); for (User user : loadedCustomerUsersEmail1) { doDelete("/api/user/"+user.getId().getId().toString()) .andExpect(status().isOk()); } pageLink = new TextPageLink(4, email1); pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", new TypeReference<TextPageData<User>>(){}, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); for (User user : loadedCustomerUsersEmail2) { doDelete("/api/user/"+user.getId().getId().toString()) .andExpect(status().isOk()); } pageLink = new TextPageLink(4, email2); pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", new TypeReference<TextPageData<User>>(){}, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); doDelete("/api/customer/"+customerId.getId().toString()) .andExpect(status().isOk()); loginSysAdmin(); doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) .andExpect(status().isOk()); } }