Commit 74b36c0b authored by Matija Obreza's avatar Matija Obreza
Browse files

Migration of data to new app-blocks:1.3 for ACL

- Users, OAuthClient are AclSid
- Roles are AclSid
- DB: Old permissions and object ownership migrated to new schema
- Permission editor
- Services cleanup
parent 9bcbdcf0
......@@ -20,6 +20,7 @@ import java.beans.Transient;
import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Table;
......@@ -34,6 +35,7 @@ import org.genesys2.server.servlet.controller.rest.serialization.UserSerializer;
@Entity
@Table(name = "\"user\"")
@JsonSerialize(using = UserSerializer.class)
@DiscriminatorValue(value = "1")
public class User extends BasicUser<UserRole> {
private static final long serialVersionUID = 4564013753931115445L;
......
......@@ -46,9 +46,6 @@ public interface UserService extends BasicUserService<UserRole, User> {
UserWrapper getWrappedById(long userId) throws UserException;
@PreAuthorize("hasRole('ADMINISTRATOR') || principal.id == #userId")
User updateData(long userId, String name, String email) throws UserException;
User getSystemUser(String string);
Page<User> listUsers(Pageable pageable);
......
......@@ -174,6 +174,19 @@ public class UserServiceImpl extends BasicUserServiceImpl<UserRole, User> implem
userWrapper.setRoles(roles);
return userWrapper;
}
@Override
@Transactional
@PreAuthorize("hasRole('ADMINISTRATOR') || principal.id == #user.id")
public User updateUser(User user, String email, String fullName) throws UserException {
if (!emailValidator.isValid(email)) {
LOG.warn("Invalid email provided: {}", email);
throw new UserException("Invalid email provided: " + email);
}
return super.updateUser(user, email, fullName);
}
protected void updateUser(User user) throws UserException {
try {
......@@ -187,28 +200,6 @@ public class UserServiceImpl extends BasicUserServiceImpl<UserRole, User> implem
}
}
@Override
@PreAuthorize("hasRole('ADMINISTRATOR') || principal.id == #userId")
@Transactional(readOnly = false, rollbackFor = NotUniqueUserException.class)
public User updateData(long userId, String name, String email) throws UserException {
final User user = userRepository.findOne(userId);
if (user == null) {
throw new UserException("No user with id=" + userId);
}
if (!emailValidator.isValid(email)) {
LOG.warn("Invalid email provided: {}", email);
throw new UserException("Invalid email provided: " + email);
}
if (!StringUtils.equals(email, user.getEmail()) && userRepository.findByEmail(email) != null) {
throw new NotUniqueUserException(new Throwable(), email);
}
user.setFullName(name);
user.setEmail(email);
userRepository.save(user);
return user;
}
@Override
@Transactional
......
......@@ -19,7 +19,6 @@ package org.genesys2.server.servlet.controller;
import org.genesys.blocks.security.model.AclObjectIdentity;
import org.genesys.blocks.security.service.CustomAclService;
import org.genesys2.server.model.UserRole;
import org.genesys2.server.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.security.access.prepost.PreAuthorize;
......@@ -38,9 +37,6 @@ public class AclEditController extends BaseController {
@Autowired
private CustomAclService aclService;
@Autowired
private UserService userService;
@RequestMapping("/{clazz}/{id}/permissions")
public String permissions(ModelMap model, @PathVariable(value = "clazz") String className, @PathVariable("id") long id,
@RequestParam(value = "back", required = false) String backUrl) {
......
......@@ -24,6 +24,7 @@ import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.genesys.blocks.security.NotUniqueUserException;
import org.genesys.blocks.security.UserException;
import org.genesys.blocks.security.model.BasicUser.AccountType;
import org.genesys.blocks.security.service.PasswordPolicy.PasswordPolicyException;
import org.genesys2.server.model.UserRole;
......@@ -263,10 +264,13 @@ public class UserProfileController extends BaseController {
}
try {
user = userService.updateUser(user, email, fullName);
user = userService.updateUser(user, email, fullName);
} catch (NotUniqueUserException e) {
redirectAttributes.addFlashAttribute("emailError", "User with e-mail address " + e.getEmail() + " already exists");
return "redirect:/profile/" + user.getUuid() + "/edit";
} catch (UserException e) {
redirectAttributes.addFlashAttribute("emailError", e.getMessage());
return "redirect:/profile/" + user.getUuid() + "/edit";
}
if (StringUtils.isNotBlank(pwd1) || StringUtils.isNotBlank(pwd2)) {
......
......@@ -174,6 +174,9 @@ public class UserProfileController extends BaseController {
} catch (NotUniqueUserException e) {
redirectAttributes.addFlashAttribute("emailError", "User with e-mail address " + e.getEmail() + " already exists");
return "redirect:" + URLBASE + user.getUuid() + "/edit";
} catch (UserException e) {
redirectAttributes.addFlashAttribute("emailError", e.getMessage());
return "redirect:" + URLBASE + user.getUuid() + "/edit";
}
if (StringUtils.isNotBlank(pwd1)) {
......
......@@ -87,19 +87,19 @@ public class PermissionController extends RestController {
}
@RequestMapping(value = "/autocompleteuser", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody Map<Long, String> acUser(@RequestParam("term") String email) {
final Map<Long, String> userIds = new HashMap<>();
public @ResponseBody Map<String, Long> acUser(@RequestParam("term") String email) {
final Map<String, Long> userIds = new HashMap<>();
for (User user : userService.autocompleteUser(email)) {
userIds.put(user.getId(), user.getEmail());
userIds.put(user.getEmail(), user.getId());
}
return userIds;
}
@RequestMapping(value = "/autocomplete-oauth-client", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody Map<String, String> acOauthClient(@RequestParam("term") String title) {
final Map<String, String> oauthMap = new HashMap<>();
public @ResponseBody Map<String, Long> acOauthClient(@RequestParam("term") String title) {
final Map<String, Long> oauthMap = new HashMap<>();
for (final OAuthClient client : clientDetailsService.autocompleteClients(title)) {
oauthMap.put(client.getTitle(), client.getClientId());
oauthMap.put(client.getTitle(), client.getId());
}
return oauthMap;
}
......
......@@ -35,7 +35,6 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
......@@ -100,13 +99,10 @@ public class UsersController extends RestController {
}
try {
userService.updateData(user.getId(), userData.getName(), userData.getEmail());
userService.updateUser(user, userData.getEmail(), userData.getName());
} catch (NotUniqueUserException e) {
LOG.warn("User with e-mail address {} already exists", e.getEmail());
throw e;
} catch (UserException e) {
LOG.warn("E-mail address is incorrect");
throw e;
}
if (StringUtils.isNotBlank(userData.getPwd1())) {
......
......@@ -858,3 +858,280 @@ databaseChangeLog:
- sql:
comment: if article#slug=='user.reset-password-instructions' update to article#slug='user-reset-password-instructions'
sql: update article set slug = 'user-reset-password-instructions' where slug = 'user.reset-password-instructions';
# User and OAuthClient extend AclSid
- changeSet:
id: 1509390480000-1
author: matijaobreza
comment: Migrate ACL to app-blocks-1.3-SNAPSHOT
changes:
- dropForeignKeyConstraint:
baseTableName: acl_entry
constraintName: FK_fhuoesmjef3mrv0gpja4shvcr
- dropForeignKeyConstraint:
baseTableName: acl_entry
constraintName: FK_i6xyfccd4y3wlwhgwpo4a9rm1
- dropForeignKeyConstraint:
baseTableName: acl_object_identity
constraintName: FK_nxv5we2ion9fwedbkge7syoc3
- dropUniqueConstraint:
tableName: acl_entry
constraintName: UK_gh5egfpe4gaqokya6s0567b0l
- renameTable:
oldTableName: acl_sid
newTableName: acl_sid_backup
- renameTable:
oldTableName: acl_entry
newTableName: acl_entry_backup
- createTable:
columns:
- column:
constraints:
nullable: true
name: type
type: INT
- column:
autoIncrement: true
constraints:
primaryKey: true
name: id
type: BIGINT
- column:
constraints:
nullable: false
name: active
type: BIT(1)
defaultValue: true
- column:
constraints:
nullable: false
name: version
type: INT
- column:
name: createdBy
type: BIGINT
- column:
name: createdDate
type: datetime(6)
- column:
name: lastModifiedBy
type: BIGINT
- column:
name: lastModifiedDate
type: datetime(6)
- column:
constraints:
nullable: false
name: principal
type: BIT(1)
- column:
constraints:
nullable: false
name: sid
type: VARCHAR(100)
tableName: acl_sid
- createTable:
columns:
- column:
autoIncrement: true
constraints:
primaryKey: true
name: id
type: BIGINT
- column:
constraints:
nullable: false
name: ace_order
type: BIGINT
- column:
constraints:
nullable: false
name: audit_failure
type: BIT(1)
- column:
constraints:
nullable: false
name: audit_success
type: BIT(1)
- column:
constraints:
nullable: false
name: granting
type: BIT(1)
- column:
constraints:
nullable: false
name: mask
type: BIGINT
- column:
constraints:
nullable: false
name: acl_object_identity
type: BIGINT
- column:
constraints:
nullable: false
name: sid
type: BIGINT
tableName: acl_entry
- addUniqueConstraint:
columnNames: acl_object_identity, ace_order
constraintName: UK_gh5egfpe4gaqokya6s0567b0l
tableName: acl_entry
# Migrate User data to AclSid
- sql:
comment: Migrate all users with their existing IDs to acl_sid
sql: >-
insert into acl_sid
(type, id, active, version, createdBy, createdDate, lastModifiedBy,
lastModifiedDate, principal, sid)
select
1, id, active, version, createdBy, createdDate, lastModifiedBy,
lastModifiedDate, true, uuid
from user;
- addForeignKeyConstraint:
baseColumnNames: id
baseTableName: user
constraintName: FK_8qtpnv06elxuryeuv1ac4ximm
deferrable: false
initiallyDeferred: false
onDelete: NO ACTION
onUpdate: NO ACTION
referencedColumnNames: id
referencedTableName: acl_sid
- dropColumn:
tableName: user
columnName: active
- dropColumn:
tableName: user
columnName: version
- dropColumn:
tableName: user
columnName: createdBy
- dropColumn:
tableName: user
columnName: createdDate
- dropColumn:
tableName: user
columnName: lastModifiedBy
- dropColumn:
tableName: user
columnName: lastModifiedDate
# Migrate OAuthClient data to AclSid
- sql:
comment: Migrate OAuthClient to AclSid, they get new IDs, but we can find them with clientId as acl_sid.sid
sql: >-
insert into acl_sid
(type, active, version, createdBy, createdDate, lastModifiedBy,
lastModifiedDate, principal, sid)
select
2, active, version, createdBy, createdDate, lastModifiedBy,
lastModifiedDate, true, clientId
from oauthclient;
- sql:
comment: Update OAuthClient#id values to their new IDs as per acl_sid
sql: >-
update oauthclient oa
join acl_sid sid on sid.sid=oa.clientId
set oa.id=sid.id
- addForeignKeyConstraint:
baseColumnNames: id
baseTableName: oauthclient
constraintName: FK_j9t6kj0254t7knyn57orqyaxk
deferrable: false
initiallyDeferred: false
onDelete: NO ACTION
onUpdate: NO ACTION
referencedColumnNames: id
referencedTableName: acl_sid
- dropColumn:
tableName: oauthclient
columnName: active
- dropColumn:
tableName: oauthclient
columnName: version
- dropColumn:
tableName: oauthclient
columnName: createdBy
- dropColumn:
tableName: oauthclient
columnName: createdDate
- dropColumn:
tableName: oauthclient
columnName: lastModifiedBy
- dropColumn:
tableName: oauthclient
columnName: lastModifiedDate
# Migrate acl_object_identity#owner_sid because these have changed
- sql:
comment: Migrate acl_object_identity#owner_sid because these have changed
sql: >-
update acl_object_identity oid
join acl_sid_backup oldsid on oldsid.id=oid.owner_sid
join acl_sid newsid on newsid.sid=oldsid.sid
set oid.owner_sid=newsid.id
- addForeignKeyConstraint:
baseColumnNames: owner_sid
baseTableName: acl_object_identity
constraintName: FK_nxv5we2ion9fwedbkge7syoc3
deferrable: false
initiallyDeferred: false
onDelete: NO ACTION
onUpdate: NO ACTION
referencedColumnNames: id
referencedTableName: acl_sid
# Migrate acl_sid_backup data for authorities (roles) -- i.e. everything that has not moved
- sql:
comment: Delete invalid authority records from acl_sid_backup (users and oauthclients)
sql: >-
delete oldsid from acl_sid_backup oldsid
inner join acl_sid newsid on newsid.sid=oldsid.sid
where oldsid.principal = 0;
- sql:
comment: Generate new acl_sid for ROLE entries (AclSid.type==0)
sql: >-
insert into acl_sid
(type, active, version, createdBy, createdDate, lastModifiedBy,
lastModifiedDate, principal, sid)
select
0, 1, 0, null, now(), null,
now(), false, sid
from acl_sid_backup where principal = 0;
# Migrate acl_entry data
- sql:
comment: Migrate acl_entry_backup data to acl_entry, using new acl_sid#id instead of the old one
sql: >-
insert into acl_entry
(ace_order, audit_failure, audit_success, granting, mask, acl_object_identity, sid)
select
e.ace_order, e.audit_failure, e.audit_success, e.granting, e.mask, e.acl_object_identity, newsid.id
from acl_entry_backup e
inner join acl_sid_backup oldsid on oldsid.id=e.sid
inner join acl_sid newsid on newsid.sid=oldsid.sid;
- dropTable:
tableName: acl_sid_backup
- dropTable:
tableName: acl_entry_backup
# Activate FK constraints
- addForeignKeyConstraint:
baseColumnNames: acl_object_identity
baseTableName: acl_entry
constraintName: FK_fhuoesmjef3mrv0gpja4shvcr
deferrable: false
initiallyDeferred: false
onDelete: NO ACTION
onUpdate: NO ACTION
referencedColumnNames: id
referencedTableName: acl_object_identity
- addForeignKeyConstraint:
baseColumnNames: sid
baseTableName: acl_entry
constraintName: FK_i6xyfccd4y3wlwhgwpo4a9rm1
deferrable: false
initiallyDeferred: false
onDelete: NO ACTION
onUpdate: NO ACTION
referencedColumnNames: id
referencedTableName: acl_sid
......@@ -15,7 +15,9 @@
<p>
<spring:message code="acl.owner"/>:
<c:out value="${jspHelper.aclSidById(aclObjectIdentity.ownerSid.id).fullName}"/>
<c:set var="sid" value="${jspHelper.aclSidById(aclObjectIdentity.ownerSid.id)}" />
<c:out value="${sid.fullName}"/>
<c:catch><a href="<c:url value='mailto:${sid.email}' />"><c:out value="${sid.email}" /></a></c:catch>
</p>
<table class="table table-striped">
<thead>
......@@ -29,9 +31,11 @@
<tbody>
<c:forEach items="${aclSids}" var="aclSid" varStatus="status">
<c:set var="sid" value="${jspHelper.aclSidById(aclSid.id)}" />
<tr class="${status.count % 2 == 0 ? 'even' : 'odd'}">
<td>
<c:out value="${jspHelper.aclSidById(aclSid.id).fullName}"/>
<c:out value="${sid.fullName}"/>
<c:catch><a href="<c:url value='mailto:${sid.email}' />"><c:out value="${sid.email}" /></a></c:catch>
</td>
<input type="hidden" name="sid" class="aclSid" value="${aclSid.id}"/>
......
......@@ -15,7 +15,8 @@
**/
package org.genesys2.tests.unit;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
......@@ -127,7 +128,7 @@ public class UserServiceTest extends AbstractServicesTest {
}
@Test
public void updateUserTest() throws PasswordPolicyException, NotUniqueUserException {
public void updateUserTest() throws UserException {
User userFromDB = userService.getUserByEmail(email);
String newFullName = "New Name";
String newEmail = "user@newemail";
......@@ -147,7 +148,7 @@ public class UserServiceTest extends AbstractServicesTest {
fullName = "This is new name";
email = "newMail@new.com";
userService.updateData(userFromDB.getId(), fullName, email);
userService.updateUser(userFromDB, email, fullName);
userFromDB = userService.getUserByEmail(email);
assertTrue(userFromDB.getFullName().equals(fullName));
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment