@@ -34,15 +34,14 @@ import static org.sonar.api.PropertyType.STRING; | |||
public class GitHubSettings { | |||
private static final String CLIENT_ID = "sonar.auth.github.clientId.secured"; | |||
private static final String CLIENT_SECRET = "sonar.auth.github.clientSecret.secured"; | |||
private static final String ENABLED = "sonar.auth.github.enabled"; | |||
private static final String ALLOW_USERS_TO_SIGN_UP = "sonar.auth.github.allowUsersToSignUp"; | |||
private static final String GROUPS_SYNC = "sonar.auth.github.groupsSync"; | |||
private static final String API_URL = "sonar.auth.github.apiUrl"; | |||
private static final String WEB_URL = "sonar.auth.github.webUrl"; | |||
private static final String ORGANIZATIONS = "sonar.auth.github.organizations"; | |||
public static final String CLIENT_ID = "sonar.auth.github.clientId.secured"; | |||
public static final String CLIENT_SECRET = "sonar.auth.github.clientSecret.secured"; | |||
public static final String ENABLED = "sonar.auth.github.enabled"; | |||
public static final String ALLOW_USERS_TO_SIGN_UP = "sonar.auth.github.allowUsersToSignUp"; | |||
public static final String GROUPS_SYNC = "sonar.auth.github.groupsSync"; | |||
public static final String API_URL = "sonar.auth.github.apiUrl"; | |||
public static final String WEB_URL = "sonar.auth.github.webUrl"; | |||
public static final String ORGANIZATIONS = "sonar.auth.github.organizations"; | |||
private static final String CATEGORY = CoreProperties.CATEGORY_ALM_INTEGRATION; | |||
private static final String SUBCATEGORY = "github"; |
@@ -32,12 +32,12 @@ import static org.sonar.api.PropertyType.PASSWORD; | |||
public class GitLabSettings { | |||
static final String GITLAB_AUTH_ENABLED = "sonar.auth.gitlab.enabled"; | |||
static final String GITLAB_AUTH_URL = "sonar.auth.gitlab.url"; | |||
static final String GITLAB_AUTH_APPLICATION_ID = "sonar.auth.gitlab.applicationId.secured"; | |||
static final String GITLAB_AUTH_SECRET = "sonar.auth.gitlab.secret.secured"; | |||
static final String GITLAB_AUTH_ALLOW_USERS_TO_SIGNUP = "sonar.auth.gitlab.allowUsersToSignUp"; | |||
static final String GITLAB_AUTH_SYNC_USER_GROUPS = "sonar.auth.gitlab.groupsSync"; | |||
public static final String GITLAB_AUTH_ENABLED = "sonar.auth.gitlab.enabled"; | |||
public static final String GITLAB_AUTH_URL = "sonar.auth.gitlab.url"; | |||
public static final String GITLAB_AUTH_APPLICATION_ID = "sonar.auth.gitlab.applicationId.secured"; | |||
public static final String GITLAB_AUTH_SECRET = "sonar.auth.gitlab.secret.secured"; | |||
public static final String GITLAB_AUTH_ALLOW_USERS_TO_SIGNUP = "sonar.auth.gitlab.allowUsersToSignUp"; | |||
public static final String GITLAB_AUTH_SYNC_USER_GROUPS = "sonar.auth.gitlab.groupsSync"; | |||
private static final String CATEGORY = CoreProperties.CATEGORY_ALM_INTEGRATION; | |||
private static final String SUBCATEGORY = "gitlab"; |
@@ -33,21 +33,21 @@ import static org.sonar.api.PropertyType.PASSWORD; | |||
@ServerSide | |||
public class SamlSettings { | |||
private static final String ENABLED = "sonar.auth.saml.enabled"; | |||
private static final String PROVIDER_ID = "sonar.auth.saml.providerId"; | |||
private static final String PROVIDER_NAME = "sonar.auth.saml.providerName"; | |||
public static final String ENABLED = "sonar.auth.saml.enabled"; | |||
public static final String PROVIDER_ID = "sonar.auth.saml.providerId"; | |||
public static final String PROVIDER_NAME = "sonar.auth.saml.providerName"; | |||
private static final String APPLICATION_ID = "sonar.auth.saml.applicationId"; | |||
private static final String LOGIN_URL = "sonar.auth.saml.loginUrl"; | |||
private static final String CERTIFICATE = "sonar.auth.saml.certificate.secured"; | |||
public static final String APPLICATION_ID = "sonar.auth.saml.applicationId"; | |||
public static final String LOGIN_URL = "sonar.auth.saml.loginUrl"; | |||
public static final String CERTIFICATE = "sonar.auth.saml.certificate.secured"; | |||
private static final String USER_LOGIN_ATTRIBUTE = "sonar.auth.saml.user.login"; | |||
private static final String USER_NAME_ATTRIBUTE = "sonar.auth.saml.user.name"; | |||
private static final String USER_EMAIL_ATTRIBUTE = "sonar.auth.saml.user.email"; | |||
private static final String GROUP_NAME_ATTRIBUTE = "sonar.auth.saml.group.name"; | |||
public static final String USER_LOGIN_ATTRIBUTE = "sonar.auth.saml.user.login"; | |||
public static final String USER_NAME_ATTRIBUTE = "sonar.auth.saml.user.name"; | |||
public static final String USER_EMAIL_ATTRIBUTE = "sonar.auth.saml.user.email"; | |||
public static final String GROUP_NAME_ATTRIBUTE = "sonar.auth.saml.group.name"; | |||
private static final String CATEGORY = "security"; | |||
private static final String SUBCATEGORY = "saml"; | |||
public static final String CATEGORY = "security"; | |||
public static final String SUBCATEGORY = "saml"; | |||
private final Configuration configuration; | |||
@@ -26,6 +26,7 @@ import org.sonar.core.platform.Module; | |||
import org.sonar.db.alm.pat.AlmPatDao; | |||
import org.sonar.db.alm.setting.AlmSettingDao; | |||
import org.sonar.db.alm.setting.ProjectAlmSettingDao; | |||
import org.sonar.db.audit.AuditDao; | |||
import org.sonar.db.ce.CeActivityDao; | |||
import org.sonar.db.ce.CeQueueDao; | |||
import org.sonar.db.ce.CeScannerContextDao; | |||
@@ -98,6 +99,7 @@ public class DaoModule extends Module { | |||
AnalysisPropertiesDao.class, | |||
AuthorizationDao.class, | |||
ApplicationProjectsDao.class, | |||
AuditDao.class, | |||
BranchDao.class, | |||
CeActivityDao.class, | |||
CeQueueDao.class, |
@@ -24,6 +24,7 @@ import java.util.Map; | |||
import org.sonar.db.alm.pat.AlmPatDao; | |||
import org.sonar.db.alm.setting.AlmSettingDao; | |||
import org.sonar.db.alm.setting.ProjectAlmSettingDao; | |||
import org.sonar.db.audit.AuditDao; | |||
import org.sonar.db.ce.CeActivityDao; | |||
import org.sonar.db.ce.CeQueueDao; | |||
import org.sonar.db.ce.CeScannerContextDao; | |||
@@ -100,6 +101,7 @@ public class DbClient { | |||
private final PropertiesDao propertiesDao; | |||
private final AlmSettingDao almSettingDao; | |||
private final AlmPatDao almPatDao; | |||
private final AuditDao auditDao; | |||
private final ProjectAlmSettingDao projectAlmSettingDao; | |||
private final InternalComponentPropertiesDao internalComponentPropertiesDao; | |||
private final InternalPropertiesDao internalPropertiesDao; | |||
@@ -169,6 +171,7 @@ public class DbClient { | |||
map.put(dao.getClass(), dao); | |||
} | |||
almSettingDao = getDao(map, AlmSettingDao.class); | |||
auditDao = getDao(map, AuditDao.class); | |||
almPatDao = getDao(map, AlmPatDao.class); | |||
projectAlmSettingDao = getDao(map, ProjectAlmSettingDao.class); | |||
schemaMigrationDao = getDao(map, SchemaMigrationDao.class); | |||
@@ -255,6 +258,10 @@ public class DbClient { | |||
return applicationProjectsDao; | |||
} | |||
public AuditDao auditDao() { | |||
return auditDao; | |||
} | |||
public ProjectAlmSettingDao projectAlmSettingDao() { | |||
return projectAlmSettingDao; | |||
} |
@@ -37,6 +37,7 @@ import org.sonar.api.Startable; | |||
import org.sonar.db.alm.pat.AlmPatMapper; | |||
import org.sonar.db.alm.setting.AlmSettingMapper; | |||
import org.sonar.db.alm.setting.ProjectAlmSettingMapper; | |||
import org.sonar.db.audit.AuditMapper; | |||
import org.sonar.db.ce.CeActivityMapper; | |||
import org.sonar.db.ce.CeQueueMapper; | |||
import org.sonar.db.ce.CeScannerContextMapper; | |||
@@ -223,6 +224,7 @@ public class MyBatis implements Startable { | |||
AlmSettingMapper.class, | |||
AnalysisPropertiesMapper.class, | |||
ApplicationProjectsMapper.class, | |||
AuditMapper.class, | |||
AuthorizationMapper.class, | |||
BranchMapper.class, | |||
CeActivityMapper.class, |
@@ -0,0 +1,73 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.audit; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.core.util.UuidFactory; | |||
import org.sonar.db.Dao; | |||
import org.sonar.db.DbSession; | |||
import java.util.List; | |||
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.MAX_SIZE; | |||
public class AuditDao implements Dao { | |||
public static final int DEFAULT_PAGE_SIZE = 10000; | |||
public static final String EXCEEDED_LENGTH = "{ \"valueLengthExceeded\": true }"; | |||
private final UuidFactory uuidFactory; | |||
private final System2 system2; | |||
public AuditDao(System2 system2, UuidFactory uuidFactory) { | |||
this.system2 = system2; | |||
this.uuidFactory = uuidFactory; | |||
} | |||
private static AuditMapper getMapper(DbSession dbSession) { | |||
return dbSession.getMapper(AuditMapper.class); | |||
} | |||
public List<AuditDto> selectAll(DbSession dbSession) { | |||
return getMapper(dbSession).selectAll(); | |||
} | |||
public List<AuditDto> selectByPeriod(DbSession dbSession, long beginning, long end) { | |||
return getMapper(dbSession).selectByPeriod(beginning, end); | |||
} | |||
public List<AuditDto> selectIfBeforeSelectedDate(DbSession dbSession, long end) { | |||
return getMapper(dbSession).selectIfBeforeSelectedDate(end); | |||
} | |||
public void insert(DbSession dbSession, AuditDto auditDto) { | |||
long now = system2.now(); | |||
auditDto.setUuid(uuidFactory.create()); | |||
auditDto.setCreatedAt(now); | |||
if (auditDto.getNewValue().length() > MAX_SIZE) { | |||
auditDto.setNewValue(EXCEEDED_LENGTH); | |||
} | |||
getMapper(dbSession).insert(auditDto); | |||
} | |||
public void deleteIfBeforeSelectedDate(DbSession dbSession, long timestamp) { | |||
getMapper(dbSession).deleteIfBeforeSelectedDate(timestamp); | |||
} | |||
} |
@@ -0,0 +1,89 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.audit; | |||
import javax.annotation.Nullable; | |||
public class AuditDto { | |||
private String uuid; | |||
private String userUuid; | |||
private String userLogin; | |||
private String category; | |||
private String operation; | |||
private String newValue; | |||
private long createdAt; | |||
public String getUuid() { | |||
return uuid; | |||
} | |||
public void setUuid(String uuid) { | |||
this.uuid = uuid; | |||
} | |||
public String getUserUuid() { | |||
return userUuid; | |||
} | |||
public void setUserUuid(@Nullable String userUuid) { | |||
this.userUuid = userUuid; | |||
} | |||
public String getUserLogin() { | |||
return userLogin; | |||
} | |||
public void setUserLogin(@Nullable String userLogin) { | |||
this.userLogin = userLogin; | |||
} | |||
public String getCategory() { | |||
return category; | |||
} | |||
public void setCategory(String category) { | |||
this.category = category; | |||
} | |||
public String getOperation() { | |||
return operation; | |||
} | |||
public void setOperation(String operation) { | |||
this.operation = operation; | |||
} | |||
public String getNewValue() { | |||
return newValue; | |||
} | |||
public void setNewValue(String newValue) { | |||
this.newValue = newValue; | |||
} | |||
public long getCreatedAt() { | |||
return createdAt; | |||
} | |||
public void setCreatedAt(long createdAt) { | |||
this.createdAt = createdAt; | |||
} | |||
} |
@@ -0,0 +1,40 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.audit; | |||
import org.apache.ibatis.annotations.Param; | |||
import java.util.List; | |||
public interface AuditMapper { | |||
List<AuditDto> selectAll(); | |||
List<AuditDto> selectByPeriod(@Param("start") long start, @Param("end") long end); | |||
List<AuditDto> selectIfBeforeSelectedDate(@Param("end") long end); | |||
void insert(@Param("dto") AuditDto auditDto); | |||
void delete(@Param("uuids") List<String> uuids); | |||
void deleteIfBeforeSelectedDate(@Param("timestamp") long timestamp); | |||
} |
@@ -0,0 +1,58 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.audit; | |||
import org.sonar.core.extension.PlatformLevel; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.audit.model.NewValue; | |||
@PlatformLevel(1) | |||
public interface AuditPersister { | |||
void addUserGroup(DbSession dbSession, NewValue newValue); | |||
void updateUserGroup(DbSession dbSession, NewValue newValue); | |||
void deleteUserGroup(DbSession dbSession, NewValue newValue); | |||
void addUser(DbSession dbSession, NewValue newValue); | |||
void updateUser(DbSession dbSession, NewValue newValue); | |||
void deactivateUser(DbSession dbSession, NewValue newValue); | |||
void addUserToGroup(DbSession dbSession, NewValue newValue); | |||
void deleteUserFromGroup(DbSession dbSession, NewValue newValue); | |||
void addUserProperty(DbSession dbSession, NewValue newValue); | |||
void updateUserProperty(DbSession dbSession, NewValue newValue); | |||
void deleteUserProperty(DbSession dbSession, NewValue newValue); | |||
void addUserToken(DbSession dbSession, NewValue newValue); | |||
void updateUserToken(DbSession dbSession, NewValue newValue); | |||
void deleteUserToken(DbSession dbSession, NewValue newValue); | |||
boolean isTrackedProperty(String propertyKey); | |||
} |
@@ -0,0 +1,41 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.audit.model; | |||
import static com.google.common.base.Strings.isNullOrEmpty; | |||
public interface NewValue { | |||
default void addField(StringBuilder sb, String field, String value, boolean isString) { | |||
if (!isNullOrEmpty(value)) { | |||
sb.append(field); | |||
addQuote(sb, isString); | |||
sb.append(value); | |||
addQuote(sb, isString); | |||
sb.append(","); | |||
} | |||
} | |||
private static void addQuote(StringBuilder sb, boolean isString) { | |||
if(isString) { | |||
sb.append("'"); | |||
} | |||
} | |||
} |
@@ -0,0 +1,67 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.audit.model; | |||
import org.sonar.db.user.UserPropertyDto; | |||
public class PropertyNewValue implements NewValue { | |||
private String propertyKey; | |||
private String propertyValue; | |||
private String userUuid; | |||
private String userLogin; | |||
public PropertyNewValue(UserPropertyDto userPropertyDto, String login) { | |||
this.propertyKey = userPropertyDto.getKey(); | |||
this.userUuid = userPropertyDto.getUserUuid(); | |||
this.userLogin = login; | |||
if(!propertyKey.contains(".secured")) { | |||
this.propertyValue = userPropertyDto.getValue(); | |||
} | |||
} | |||
public String getPropertyKey() { | |||
return this.propertyKey; | |||
} | |||
public String getPropertyValue() { | |||
return this.propertyValue; | |||
} | |||
public String getUserUuid() { | |||
return this.userUuid; | |||
} | |||
public String getUserLogin() { | |||
return this.userLogin; | |||
} | |||
@Override | |||
public String toString() { | |||
StringBuilder sb = new StringBuilder("{"); | |||
addField(sb, "'propertyKey':", this.propertyKey, true); | |||
addField(sb, "'propertyValue':", this.propertyValue, true); | |||
addField(sb, "'userUuid':", this.userUuid, true); | |||
addField(sb, "'userLogin':", this.userLogin, true); | |||
sb.append("}"); | |||
return sb.toString(); | |||
} | |||
} |
@@ -0,0 +1,95 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.audit.model; | |||
import org.sonar.db.user.GroupDto; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.db.user.UserGroupDto; | |||
public class UserGroupNewValue implements NewValue { | |||
private String groupUuid; | |||
private String name; | |||
private String description; | |||
private String userUuid; | |||
private String userLogin; | |||
public UserGroupNewValue(String groupUuid, String name) { | |||
this.groupUuid = groupUuid; | |||
this.name = name; | |||
} | |||
public UserGroupNewValue(GroupDto groupDto) { | |||
this.groupUuid = groupDto.getUuid(); | |||
this.name = groupDto.getName(); | |||
this.description = groupDto.getDescription(); | |||
} | |||
public UserGroupNewValue(GroupDto groupDto, UserDto userDto) { | |||
this.groupUuid = groupDto.getUuid(); | |||
this.name = groupDto.getName(); | |||
this.userUuid = userDto.getUuid(); | |||
this.userLogin = userDto.getLogin(); | |||
} | |||
public UserGroupNewValue(UserDto userDto) { | |||
this.userUuid = userDto.getUuid(); | |||
this.userLogin = userDto.getLogin(); | |||
} | |||
public UserGroupNewValue(UserGroupDto userGroupDto, String groupName, String userLogin) { | |||
this.groupUuid = userGroupDto.getGroupUuid(); | |||
this.userUuid = userGroupDto.getUserUuid(); | |||
this.name = groupName; | |||
this.userLogin = userLogin; | |||
} | |||
public String getGroupUuid() { | |||
return this.groupUuid; | |||
} | |||
public String getName() { | |||
return this.name; | |||
} | |||
public String getDescription() { | |||
return this.description; | |||
} | |||
public String getUserUuid() { | |||
return this.userUuid; | |||
} | |||
public String getUserLogin() { | |||
return this.userLogin; | |||
} | |||
@Override | |||
public String toString() { | |||
StringBuilder sb = new StringBuilder("{"); | |||
addField(sb, "'groupUuid':", this.groupUuid, true); | |||
addField(sb, "'name':", this.name, true); | |||
addField(sb, "'description':", this.description, true); | |||
addField(sb, "'userUuid':", this.userUuid, true); | |||
addField(sb, "'userLogin':", this.userLogin, true); | |||
sb.append("}"); | |||
return sb.toString(); | |||
} | |||
} |
@@ -0,0 +1,133 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.audit.model; | |||
import org.apache.commons.lang.ObjectUtils; | |||
import org.sonar.db.user.UserDto; | |||
public class UserNewValue implements NewValue { | |||
private String userUuid; | |||
private String login; | |||
private String name; | |||
private String email; | |||
private Boolean isActive; | |||
private String scmAccounts; | |||
private String externalId; | |||
private String externalLogin; | |||
private String externalIdentityProvider; | |||
private Boolean local; | |||
private Boolean onboarded; | |||
private Boolean root; | |||
private Long lastConnectionDate; | |||
public UserNewValue(String userUuid, String userLogin) { | |||
this.userUuid = userUuid; | |||
this.login = userLogin; | |||
} | |||
public UserNewValue(UserDto userDto) { | |||
this.userUuid = userDto.getUuid(); | |||
this.login = userDto.getLogin(); | |||
this.name = userDto.getName(); | |||
this.email = userDto.getEmail(); | |||
this.isActive = userDto.isActive(); | |||
this.scmAccounts = userDto.getScmAccounts(); | |||
this.externalId = userDto.getExternalId(); | |||
this.externalLogin = userDto.getExternalLogin(); | |||
this.externalIdentityProvider = userDto.getExternalIdentityProvider(); | |||
this.local = userDto.isLocal(); | |||
this.onboarded = userDto.isOnboarded(); | |||
this.root = userDto.isRoot(); | |||
this.lastConnectionDate = userDto.getLastConnectionDate(); | |||
} | |||
public String getUserUuid() { | |||
return this.userUuid; | |||
} | |||
public String getLogin() { | |||
return this.login; | |||
} | |||
public String getName() { | |||
return this.name; | |||
} | |||
public String getEmail() { | |||
return this.email; | |||
} | |||
public boolean isActive() { | |||
return this.isActive; | |||
} | |||
public String getScmAccounts() { | |||
return this.scmAccounts; | |||
} | |||
public String getExternalId() { | |||
return this.externalId; | |||
} | |||
public String getExternalLogin() { | |||
return this.externalLogin; | |||
} | |||
public String getExternalIdentityProvider() { | |||
return this.externalIdentityProvider; | |||
} | |||
public boolean isLocal() { | |||
return this.local; | |||
} | |||
public boolean isOnboarded() { | |||
return this.onboarded; | |||
} | |||
public boolean isRoot() { | |||
return this.root; | |||
} | |||
public Long getLastConnectionDate() { | |||
return this.lastConnectionDate; | |||
} | |||
@Override | |||
public String toString() { | |||
StringBuilder sb = new StringBuilder("{"); | |||
addField(sb, "'userUuid':", this.userUuid, true); | |||
addField(sb, "'login':", this.login, true); | |||
addField(sb, "'name':", this.name, true); | |||
addField(sb, "'email':", this.email, true); | |||
addField(sb, "'isActive':", ObjectUtils.toString(this.isActive), false); | |||
addField(sb, "'scmAccounts':", this.scmAccounts, true); | |||
addField(sb, "'externalId':", this.externalId, true); | |||
addField(sb, "'externalLogin':", this.externalLogin, true); | |||
addField(sb, "'externalIdentityProvider':", this.externalIdentityProvider, true); | |||
addField(sb, "'local':", ObjectUtils.toString(this.local), false); | |||
addField(sb, "'onboarded':", ObjectUtils.toString(this.onboarded), false); | |||
addField(sb, "'root':", ObjectUtils.toString(this.root), false); | |||
addField(sb, "'lastConnectionDate':", ObjectUtils.toString(this.lastConnectionDate), false); | |||
sb.append("}"); | |||
return sb.toString(); | |||
} | |||
} |
@@ -0,0 +1,83 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.audit.model; | |||
import org.apache.commons.lang.ObjectUtils; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.db.user.UserTokenDto; | |||
public class UserTokenNewValue implements NewValue { | |||
private String tokenUuid; | |||
private String userUuid; | |||
private String userLogin; | |||
private String tokenName; | |||
private Long lastConnectionDate; | |||
public UserTokenNewValue(UserTokenDto userTokenDto, @Nullable String userLogin) { | |||
this.tokenUuid = userTokenDto.getUuid(); | |||
this.tokenName = userTokenDto.getName(); | |||
this.userUuid = userTokenDto.getUserUuid(); | |||
this.lastConnectionDate = userTokenDto.getLastConnectionDate(); | |||
this.userLogin = userLogin; | |||
} | |||
public UserTokenNewValue(UserDto userDto) { | |||
this.userUuid = userDto.getUuid(); | |||
this.userLogin = userDto.getLogin(); | |||
} | |||
public UserTokenNewValue(UserDto userDto, String tokenName) { | |||
this(userDto); | |||
this.tokenName = tokenName; | |||
} | |||
public String getTokenUuid() { | |||
return this.tokenUuid; | |||
} | |||
public String getUserUuid() { | |||
return this.userUuid; | |||
} | |||
public String getUserLogin() { | |||
return this.userLogin; | |||
} | |||
public String getTokenName() { | |||
return this.tokenName; | |||
} | |||
public Long getLastConnectionDate() { | |||
return this.lastConnectionDate; | |||
} | |||
@Override | |||
public String toString() { | |||
StringBuilder sb = new StringBuilder("{"); | |||
addField(sb, "'tokenUuid':", this.tokenUuid, true); | |||
addField(sb, "'userUuid':", this.userUuid, true); | |||
addField(sb, "'userLogin':", this.userLogin, true); | |||
addField(sb, "'tokenName':", this.tokenName, true); | |||
addField(sb, "'lastConnectionDate':", ObjectUtils.toString(this.lastConnectionDate), false); | |||
sb.append("}"); | |||
return sb.toString(); | |||
} | |||
} |
@@ -0,0 +1,23 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
@ParametersAreNonnullByDefault | |||
package org.sonar.db.audit; | |||
import javax.annotation.ParametersAreNonnullByDefault; |
@@ -33,20 +33,28 @@ import org.sonar.db.Dao; | |||
import org.sonar.db.DaoUtils; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.WildcardPosition; | |||
import org.sonar.db.audit.AuditPersister; | |||
import org.sonar.db.audit.model.UserGroupNewValue; | |||
import static org.sonar.db.DatabaseUtils.executeLargeInputs; | |||
public class GroupDao implements Dao { | |||
private final System2 system; | |||
private AuditPersister auditPersister; | |||
public GroupDao(System2 system) { | |||
this.system = system; | |||
} | |||
public GroupDao(System2 system, AuditPersister auditPersister) { | |||
this(system); | |||
this.auditPersister = auditPersister; | |||
} | |||
/** | |||
* @param dbSession | |||
* @param name non-null group name | |||
* @param name non-null group name | |||
* @return the group with the given name | |||
*/ | |||
public Optional<GroupDto> selectByName(DbSession dbSession, String name) { | |||
@@ -66,8 +74,12 @@ public class GroupDao implements Dao { | |||
return executeLargeInputs(uuids, mapper(dbSession)::selectByUuids); | |||
} | |||
public void deleteByUuid(DbSession dbSession, String groupUuid) { | |||
public void deleteByUuid(DbSession dbSession, String groupUuid, String groupName) { | |||
mapper(dbSession).deleteByUuid(groupUuid); | |||
if (auditPersister != null) { | |||
auditPersister.deleteUserGroup(dbSession, new UserGroupNewValue(groupUuid, groupName)); | |||
} | |||
} | |||
public int countByQuery(DbSession session, @Nullable String query) { | |||
@@ -83,12 +95,22 @@ public class GroupDao implements Dao { | |||
item.setCreatedAt(createdAt) | |||
.setUpdatedAt(createdAt); | |||
mapper(session).insert(item); | |||
if (auditPersister != null) { | |||
auditPersister.addUserGroup(session, new UserGroupNewValue(item.getUuid(), item.getName())); | |||
} | |||
return item; | |||
} | |||
public GroupDto update(DbSession session, GroupDto item) { | |||
item.setUpdatedAt(new Date(system.now())); | |||
mapper(session).update(item); | |||
if (auditPersister != null) { | |||
auditPersister.updateUserGroup(session, new UserGroupNewValue(item)); | |||
} | |||
return item; | |||
} | |||
@@ -34,6 +34,8 @@ import org.sonar.api.utils.System2; | |||
import org.sonar.core.util.UuidFactory; | |||
import org.sonar.db.Dao; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.audit.AuditPersister; | |||
import org.sonar.db.audit.model.UserNewValue; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.project.ProjectDto; | |||
@@ -48,11 +50,18 @@ public class UserDao implements Dao { | |||
private final System2 system2; | |||
private final UuidFactory uuidFactory; | |||
private AuditPersister auditPersister; | |||
public UserDao(System2 system2, UuidFactory uuidFactory) { | |||
this.system2 = system2; | |||
this.uuidFactory = uuidFactory; | |||
} | |||
public UserDao(System2 system2, UuidFactory uuidFactory, AuditPersister auditPersister) { | |||
this(system2, uuidFactory); | |||
this.auditPersister = auditPersister; | |||
} | |||
@CheckForNull | |||
public UserDto selectByUuid(DbSession session, String uuid) { | |||
return mapper(session).selectByUuid(uuid); | |||
@@ -105,11 +114,23 @@ public class UserDao implements Dao { | |||
public UserDto insert(DbSession session, UserDto dto) { | |||
long now = system2.now(); | |||
mapper(session).insert(dto.setUuid(uuidFactory.create()).setCreatedAt(now).setUpdatedAt(now)); | |||
if (auditPersister != null) { | |||
auditPersister.addUser(session, new UserNewValue(dto.getUuid(), dto.getLogin())); | |||
} | |||
return dto; | |||
} | |||
public UserDto update(DbSession session, UserDto dto) { | |||
return update(session, dto, true); | |||
} | |||
public UserDto update(DbSession session, UserDto dto, boolean track) { | |||
mapper(session).update(dto.setUpdatedAt(system2.now())); | |||
if (track && auditPersister != null) { | |||
auditPersister.updateUser(session, new UserNewValue(dto)); | |||
} | |||
return dto; | |||
} | |||
@@ -123,6 +144,10 @@ public class UserDao implements Dao { | |||
public void deactivateUser(DbSession dbSession, UserDto user) { | |||
mapper(dbSession).deactivateUser(user.getLogin(), system2.now()); | |||
if (auditPersister != null) { | |||
auditPersister.deactivateUser(dbSession, new UserNewValue(user.getUuid(), user.getLogin())); | |||
} | |||
} | |||
public void cleanHomepage(DbSession dbSession, ProjectDto project) { |
@@ -22,11 +22,27 @@ package org.sonar.db.user; | |||
import java.util.Set; | |||
import org.sonar.db.Dao; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.audit.AuditPersister; | |||
import org.sonar.db.audit.model.UserGroupNewValue; | |||
public class UserGroupDao implements Dao { | |||
public UserGroupDto insert(DbSession session, UserGroupDto dto) { | |||
private AuditPersister auditPersister; | |||
public UserGroupDao() { | |||
} | |||
public UserGroupDao(AuditPersister auditPersister) { | |||
this.auditPersister = auditPersister; | |||
} | |||
public UserGroupDto insert(DbSession session, UserGroupDto dto, String groupName, String login) { | |||
mapper(session).insert(dto); | |||
if (auditPersister != null) { | |||
auditPersister.addUserToGroup(session, new UserGroupNewValue(dto, groupName, login)); | |||
} | |||
return dto; | |||
} | |||
@@ -34,16 +50,28 @@ public class UserGroupDao implements Dao { | |||
return mapper(session).selectUserUuidsInGroup(groupUuid); | |||
} | |||
public void delete(DbSession session, String groupUuid, String userUuid) { | |||
mapper(session).delete(groupUuid, userUuid); | |||
public void delete(DbSession session, GroupDto group, UserDto user) { | |||
mapper(session).delete(group.getUuid(), user.getUuid()); | |||
if (auditPersister != null) { | |||
auditPersister.deleteUserFromGroup(session, new UserGroupNewValue(group, user)); | |||
} | |||
} | |||
public void deleteByGroupUuid(DbSession session, String groupUuid) { | |||
public void deleteByGroupUuid(DbSession session, String groupUuid, String groupName) { | |||
mapper(session).deleteByGroupUuid(groupUuid); | |||
if (auditPersister != null) { | |||
auditPersister.deleteUserFromGroup(session, new UserGroupNewValue(groupUuid, groupName)); | |||
} | |||
} | |||
public void deleteByUserUuid(DbSession dbSession, String userUuid) { | |||
mapper(dbSession).deleteByUserUuid(userUuid); | |||
public void deleteByUserUuid(DbSession dbSession, UserDto userDto) { | |||
mapper(dbSession).deleteByUserUuid(userDto.getUuid()); | |||
if (auditPersister != null) { | |||
auditPersister.deleteUserFromGroup(dbSession, new UserGroupNewValue(userDto)); | |||
} | |||
} | |||
private static UserGroupMapper mapper(DbSession session) { |
@@ -20,35 +20,63 @@ | |||
package org.sonar.db.user; | |||
import java.util.List; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.core.util.UuidFactory; | |||
import org.sonar.db.Dao; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.audit.AuditPersister; | |||
import org.sonar.db.audit.model.PropertyNewValue; | |||
public class UserPropertiesDao implements Dao { | |||
private final System2 system2; | |||
private final UuidFactory uuidFactory; | |||
private AuditPersister auditPersister; | |||
public UserPropertiesDao(System2 system2, UuidFactory uuidFactory) { | |||
this.system2 = system2; | |||
this.uuidFactory = uuidFactory; | |||
} | |||
public UserPropertiesDao(System2 system2, UuidFactory uuidFactory, AuditPersister auditPersister) { | |||
this(system2, uuidFactory); | |||
this.auditPersister = auditPersister; | |||
} | |||
public List<UserPropertyDto> selectByUser(DbSession session, UserDto user) { | |||
return mapper(session).selectByUserUuid(user.getUuid()); | |||
} | |||
public UserPropertyDto insertOrUpdate(DbSession session, UserPropertyDto dto) { | |||
public UserPropertyDto insertOrUpdate(DbSession session, UserPropertyDto dto, @Nullable String login) { | |||
long now = system2.now(); | |||
boolean isUpdate = true; | |||
if (mapper(session).update(dto, now) == 0) { | |||
mapper(session).insert(dto.setUuid(uuidFactory.create()), now); | |||
isUpdate = false; | |||
} | |||
if (auditPersister != null && auditPersister.isTrackedProperty(dto.getKey())) { | |||
if (isUpdate) { | |||
auditPersister.updateUserProperty(session, new PropertyNewValue(dto, login)); | |||
} else { | |||
auditPersister.addUserProperty(session, new PropertyNewValue(dto, login)); | |||
} | |||
} | |||
return dto; | |||
} | |||
public void deleteByUser(DbSession session, UserDto user) { | |||
List<UserPropertyDto> userProperties = selectByUser(session, user); | |||
mapper(session).deleteByUserUuid(user.getUuid()); | |||
if (auditPersister != null) { | |||
userProperties.stream() | |||
.filter(p -> auditPersister.isTrackedProperty(p.getKey())) | |||
.forEach(p -> auditPersister.deleteUserProperty(session, new PropertyNewValue(p, user.getLogin()))); | |||
} | |||
} | |||
private static UserPropertiesMapper mapper(DbSession session) { |
@@ -24,9 +24,12 @@ import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.sonar.core.util.UuidFactory; | |||
import org.sonar.db.Dao; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.audit.AuditPersister; | |||
import org.sonar.db.audit.model.UserTokenNewValue; | |||
import static org.sonar.core.util.stream.MoreCollectors.toList; | |||
import static org.sonar.db.DatabaseUtils.executeLargeInputs; | |||
@@ -34,18 +37,36 @@ import static org.sonar.db.DatabaseUtils.executeLargeInputs; | |||
public class UserTokenDao implements Dao { | |||
private UuidFactory uuidFactory; | |||
private AuditPersister auditPersister; | |||
public UserTokenDao(UuidFactory uuidFactory) { | |||
this.uuidFactory = uuidFactory; | |||
} | |||
public void insert(DbSession dbSession, UserTokenDto userTokenDto) { | |||
public UserTokenDao(UuidFactory uuidFactory, AuditPersister auditPersister) { | |||
this(uuidFactory); | |||
this.auditPersister = auditPersister; | |||
} | |||
public void insert(DbSession dbSession, UserTokenDto userTokenDto, String userLogin) { | |||
userTokenDto.setUuid(uuidFactory.create()); | |||
mapper(dbSession).insert(userTokenDto); | |||
if (auditPersister != null) { | |||
auditPersister.addUserToken(dbSession, new UserTokenNewValue(userTokenDto, userLogin)); | |||
} | |||
} | |||
public void update(DbSession session, UserTokenDto userTokenDto, @Nullable String userLogin) { | |||
update(session, userTokenDto, true, userLogin); | |||
} | |||
public void update(DbSession dbSession, UserTokenDto userTokenDto) { | |||
public void update(DbSession dbSession, UserTokenDto userTokenDto, boolean track, @Nullable String userLogin) { | |||
mapper(dbSession).update(userTokenDto); | |||
if (track && auditPersister != null) { | |||
auditPersister.updateUserToken(dbSession, new UserTokenNewValue(userTokenDto, userLogin)); | |||
} | |||
} | |||
@CheckForNull | |||
@@ -79,10 +100,18 @@ public class UserTokenDao implements Dao { | |||
public void deleteByUser(DbSession dbSession, UserDto user) { | |||
mapper(dbSession).deleteByUserUuid(user.getUuid()); | |||
if (auditPersister != null) { | |||
auditPersister.deleteUserToken(dbSession, new UserTokenNewValue(user)); | |||
} | |||
} | |||
public void deleteByUserAndName(DbSession dbSession, UserDto user, String name) { | |||
mapper(dbSession).deleteByUserUuidAndName(user.getUuid(), name); | |||
if (auditPersister != null) { | |||
auditPersister.deleteUserToken(dbSession, new UserTokenNewValue(user, name)); | |||
} | |||
} | |||
private static UserTokenMapper mapper(DbSession dbSession) { |
@@ -0,0 +1,67 @@ | |||
<?xml version="1.0" encoding="UTF-8" ?> | |||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd"> | |||
<mapper namespace="org.sonar.db.audit.AuditMapper"> | |||
<sql id="sqlColumns"> | |||
a.uuid as "uuid", | |||
a.user_uuid as "userUuid", | |||
a.user_login as "userLogin", | |||
a.category as "category", | |||
a.operation as "operation", | |||
a.new_value as "newValue", | |||
a.created_at as "createdAt" | |||
</sql> | |||
<select id="selectAll" resultType="org.sonar.db.audit.AuditDto"> | |||
select <include refid="sqlColumns"/> | |||
from | |||
audits a | |||
</select> | |||
<select id="selectByPeriod" parameterType="map" resultType="org.sonar.db.audit.AuditDto"> | |||
select <include refid="sqlColumns"/> | |||
from | |||
audits a | |||
where | |||
a.created_at > #{start, jdbcType=BIGINT} AND | |||
a.created_at < #{end, jdbcType=BIGINT} | |||
</select> | |||
<select id="selectIfBeforeSelectedDate" parameterType="map" resultType="org.sonar.db.audit.AuditDto"> | |||
select <include refid="sqlColumns"/> | |||
from | |||
audits a | |||
where | |||
a.created_at > #{end, jdbcType=BIGINT} | |||
</select> | |||
<insert id="insert" parameterType="Map" useGeneratedKeys="false"> | |||
INSERT INTO audits | |||
( | |||
uuid, | |||
user_uuid, | |||
user_login, | |||
category, | |||
operation, | |||
new_value, | |||
created_at | |||
) | |||
VALUES ( | |||
#{dto.uuid, jdbcType=VARCHAR}, | |||
#{dto.userUuid, jdbcType=VARCHAR}, | |||
#{dto.userLogin, jdbcType=VARCHAR}, | |||
#{dto.category, jdbcType=VARCHAR}, | |||
#{dto.operation, jdbcType=VARCHAR}, | |||
#{dto.newValue, jdbcType=VARCHAR}, | |||
#{dto.createdAt, jdbcType=BIGINT} | |||
) | |||
</insert> | |||
<delete id="deleteIfBeforeSelectedDate"> | |||
delete from audits | |||
where | |||
created_at <= #{timestamp,jdbcType=BIGINT} | |||
</delete> | |||
</mapper> |
@@ -100,6 +100,18 @@ CREATE UNIQUE INDEX "UNIQ_APP_PROJECTS" ON "APP_PROJECTS"("APPLICATION_UUID", "P | |||
CREATE INDEX "IDX_APP_PROJ_APPLICATION_UUID" ON "APP_PROJECTS"("APPLICATION_UUID"); | |||
CREATE INDEX "IDX_APP_PROJ_PROJECT_UUID" ON "APP_PROJECTS"("PROJECT_UUID"); | |||
CREATE TABLE "AUDITS"( | |||
"UUID" VARCHAR(40) NOT NULL, | |||
"USER_UUID" VARCHAR(40) NOT NULL, | |||
"USER_LOGIN" VARCHAR(255) NOT NULL, | |||
"CATEGORY" VARCHAR(20) NOT NULL, | |||
"OPERATION" VARCHAR(50) NOT NULL, | |||
"NEW_VALUE" VARCHAR(4000), | |||
"CREATED_AT" BIGINT NOT NULL | |||
); | |||
ALTER TABLE "AUDITS" ADD CONSTRAINT "PK_AUDITS" PRIMARY KEY("UUID"); | |||
CREATE INDEX "AUDITS_CREATED_AT" ON "AUDITS"("CREATED_AT"); | |||
CREATE TABLE "CE_ACTIVITY"( | |||
"UUID" VARCHAR(40) NOT NULL, | |||
"TASK_TYPE" VARCHAR(15) NOT NULL, |
@@ -0,0 +1,150 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.audit; | |||
import java.util.List; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.impl.utils.TestSystem2; | |||
import org.sonar.core.util.UuidFactory; | |||
import org.sonar.core.util.UuidFactoryImpl; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.db.audit.AuditDao.EXCEEDED_LENGTH; | |||
public class AuditDaoTest { | |||
private static final long NOW = 1000000L; | |||
private static final String A_UUID = "SOME_UUID"; | |||
private final TestSystem2 system2 = new TestSystem2().setNow(NOW); | |||
@Rule | |||
public final DbTester db = DbTester.create(system2); | |||
private final DbSession dbSession = db.getSession(); | |||
private final UuidFactory uuidFactory = mock(UuidFactory.class); | |||
private final AuditDao testAuditDao = new AuditDao(system2, UuidFactoryImpl.INSTANCE); | |||
@Test | |||
public void selectAll_oneEntryInserted_returnThisEntry() { | |||
AuditDao auditDaoDeterministicUUID = new AuditDao(system2, uuidFactory); | |||
when(uuidFactory.create()).thenReturn(A_UUID); | |||
AuditDto auditDto = AuditTesting.newAuditDto(); | |||
auditDaoDeterministicUUID.insert(dbSession, auditDto); | |||
List<AuditDto> auditDtos = auditDaoDeterministicUUID.selectAll(dbSession); | |||
assertThat(auditDtos.size()).isEqualTo(1); | |||
assertThat(auditDtos.get(0)) | |||
.extracting(AuditDto::getUuid, AuditDto::getUserLogin, | |||
AuditDto::getUserUuid, AuditDto::getCategory, | |||
AuditDto::getOperation, AuditDto::getNewValue, | |||
AuditDto::getCreatedAt) | |||
.containsExactly(A_UUID, auditDto.getUserLogin(), | |||
auditDto.getUserUuid(), auditDto.getCategory(), | |||
auditDto.getOperation(), auditDto.getNewValue(), | |||
auditDto.getCreatedAt()); | |||
} | |||
@Test | |||
public void selectAll_100EntriesInserted_100EntriesReturned() { | |||
AuditDao auditDao = new AuditDao(system2, UuidFactoryImpl.INSTANCE); | |||
for(int i=0; i<100; i++) { | |||
AuditDto auditDto = AuditTesting.newAuditDto(); | |||
auditDto.setUuid(randomAlphanumeric(20)); | |||
auditDao.insert(dbSession, auditDto); | |||
} | |||
List<AuditDto> auditDtos = auditDao.selectAll(dbSession); | |||
assertThat(auditDtos.size()).isEqualTo(100); | |||
} | |||
@Test | |||
public void selectByPeriod_selectOneRowFromTheMiddle() { | |||
prepareThreeRowsWithDeterministicCreatedAt(); | |||
List<AuditDto> auditDtos = testAuditDao.selectByPeriod(dbSession, 1, 3); | |||
assertThat(auditDtos.size()).isEqualTo(1); | |||
assertThat(auditDtos.get(0).getCreatedAt()).isEqualTo(2); | |||
} | |||
@Test | |||
public void selectByPeriod_selectOneRowFromTheEnd() { | |||
prepareThreeRowsWithDeterministicCreatedAt(); | |||
List<AuditDto> auditDtos = testAuditDao.selectByPeriod(dbSession, 2, 4); | |||
assertThat(auditDtos.size()).isEqualTo(1); | |||
assertThat(auditDtos.get(0).getCreatedAt()).isEqualTo(3); | |||
} | |||
@Test | |||
public void selectByPeriod_selectAllRows() { | |||
prepareThreeRowsWithDeterministicCreatedAt(); | |||
List<AuditDto> auditDtos = testAuditDao.selectByPeriod(dbSession, 0, 4); | |||
assertThat(auditDtos.size()).isEqualTo(3); | |||
} | |||
@Test | |||
public void selectIfBeforeSelectedDate_select1Row() { | |||
prepareThreeRowsWithDeterministicCreatedAt(); | |||
List<AuditDto> auditDtos = testAuditDao.selectIfBeforeSelectedDate(dbSession, 2); | |||
assertThat(auditDtos.size()).isEqualTo(1); | |||
} | |||
@Test | |||
public void deleteIfBeforeSelectedDate_deleteTwoRows() { | |||
prepareThreeRowsWithDeterministicCreatedAt(); | |||
testAuditDao.deleteIfBeforeSelectedDate(dbSession, 2); | |||
List<AuditDto> auditDtos = testAuditDao.selectAll(dbSession); | |||
assertThat(auditDtos.size()).isEqualTo(1); | |||
} | |||
@Test | |||
public void insert_truncateVeryLongNewValue() { | |||
AuditDto auditDto = AuditTesting.newAuditDto(); | |||
String veryLongString = randomAlphanumeric(5000); | |||
auditDto.setNewValue(veryLongString); | |||
testAuditDao.insert(dbSession, auditDto); | |||
assertThat(auditDto.getNewValue()).isEqualTo(EXCEEDED_LENGTH); | |||
} | |||
private void prepareThreeRowsWithDeterministicCreatedAt() { | |||
for(int i=1; i<=3; i++) { | |||
AuditDto auditDto = AuditTesting.newAuditDto(); | |||
system2.setNow(i); | |||
testAuditDao.insert(dbSession, auditDto); | |||
} | |||
} | |||
} |
@@ -214,7 +214,7 @@ public class GroupDaoTest { | |||
public void deleteByUuid() { | |||
db.getDbClient().groupDao().insert(dbSession, aGroup); | |||
underTest.deleteByUuid(dbSession, aGroup.getUuid()); | |||
underTest.deleteByUuid(dbSession, aGroup.getUuid(), aGroup.getName()); | |||
assertThat(db.countRowsOfTable(dbSession, "groups")).isZero(); | |||
} |
@@ -0,0 +1,107 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.user; | |||
import java.util.Date; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.mockito.ArgumentCaptor; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.audit.AuditPersister; | |||
import org.sonar.db.audit.model.UserGroupNewValue; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.ArgumentMatchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.when; | |||
public class GroupDaoWithPersisterTest { | |||
private static final long NOW = 1_500_000L; | |||
private final AuditPersister auditPersister = mock(AuditPersister.class); | |||
private final ArgumentCaptor<UserGroupNewValue> newValueCaptor = ArgumentCaptor.forClass(UserGroupNewValue.class); | |||
private final System2 system2 = mock(System2.class); | |||
@Rule | |||
public final DbTester db = DbTester.create(system2, auditPersister); | |||
private final DbClient dbClient = db.getDbClient(); | |||
private final GroupDao underTest = db.getDbClient().groupDao(); | |||
private final GroupDto aGroup = new GroupDto() | |||
.setUuid("uuid") | |||
.setName("the-name") | |||
.setDescription("the description"); | |||
@Before | |||
public void setUp() { | |||
when(system2.now()).thenReturn(NOW); | |||
} | |||
@Test | |||
public void insert_and_update() { | |||
dbClient.groupDao().insert(db.getSession(), aGroup); | |||
verify(auditPersister).addUserGroup(eq(db.getSession()), newValueCaptor.capture()); | |||
UserGroupNewValue newValue = newValueCaptor.getValue(); | |||
assertThat(newValue) | |||
.extracting(UserGroupNewValue::getGroupUuid, UserGroupNewValue::getName) | |||
.containsExactly(aGroup.getUuid(), aGroup.getName()); | |||
assertThat(newValue.toString()).doesNotContain("'description':"); | |||
GroupDto dto = new GroupDto() | |||
.setUuid(aGroup.getUuid()) | |||
.setName("new-name") | |||
.setDescription("New description") | |||
.setCreatedAt(new Date(NOW + 1_000L)); | |||
underTest.update(db.getSession(), dto); | |||
verify(auditPersister).updateUserGroup(eq(db.getSession()), newValueCaptor.capture()); | |||
newValue = newValueCaptor.getValue(); | |||
assertThat(newValue) | |||
.extracting(UserGroupNewValue::getGroupUuid, UserGroupNewValue::getName, UserGroupNewValue::getDescription) | |||
.containsExactly(dto.getUuid(), dto.getName(), dto.getDescription()); | |||
assertThat(newValue.toString()).contains("'description':"); | |||
} | |||
@Test | |||
public void deleteByUuid() { | |||
dbClient.groupDao().insert(db.getSession(), aGroup); | |||
verify(auditPersister).addUserGroup(eq(db.getSession()), any()); | |||
underTest.deleteByUuid(db.getSession(), aGroup.getUuid(), aGroup.getName()); | |||
assertThat(db.countRowsOfTable(db.getSession(), "groups")).isZero(); | |||
verify(auditPersister).deleteUserGroup(eq(db.getSession()), newValueCaptor.capture()); | |||
assertThat(newValueCaptor.getValue()) | |||
.extracting(UserGroupNewValue::getGroupUuid, UserGroupNewValue::getName) | |||
.containsExactly(aGroup.getUuid(), aGroup.getName()); | |||
} | |||
} |
@@ -785,7 +785,7 @@ public class UserDaoTest { | |||
dbClient.groupDao().insert(session, group); | |||
UserGroupDto dto = new UserGroupDto().setUserUuid(user.getUuid()).setGroupUuid(group.getUuid()); | |||
dbClient.userGroupDao().insert(session, dto); | |||
dbClient.userGroupDao().insert(session, dto, group.getName(), user.getLogin()); | |||
return dto; | |||
} | |||
} |
@@ -0,0 +1,169 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.user; | |||
import com.tngtech.java.junit.dataprovider.DataProviderRunner; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.runner.RunWith; | |||
import org.mockito.ArgumentCaptor; | |||
import org.sonar.api.impl.utils.TestSystem2; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.audit.AuditPersister; | |||
import org.sonar.db.audit.model.UserNewValue; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.ArgumentMatchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.verifyNoMoreInteractions; | |||
import static org.sonar.db.user.GroupTesting.newGroupDto; | |||
import static org.sonar.db.user.UserTesting.newUserDto; | |||
@RunWith(DataProviderRunner.class) | |||
public class UserDaoWithPersisterTest { | |||
private static final long NOW = 1_500_000_000_000L; | |||
private final AuditPersister auditPersister = mock(AuditPersister.class); | |||
private final TestSystem2 system2 = new TestSystem2().setNow(NOW); | |||
private final ArgumentCaptor<UserNewValue> newValueCaptor = ArgumentCaptor.forClass(UserNewValue.class); | |||
@Rule | |||
public final DbTester db = DbTester.create(system2, auditPersister); | |||
private final DbClient dbClient = db.getDbClient(); | |||
private final UserDao underTest = db.getDbClient().userDao(); | |||
@Test | |||
public void insert_user_with_default_values() { | |||
UserDto userDto = new UserDto() | |||
.setLogin("john") | |||
.setName("John") | |||
.setEmail("jo@hn.com") | |||
.setExternalLogin("john-1") | |||
.setExternalIdentityProvider("sonarqube") | |||
.setExternalId("EXT_ID"); | |||
underTest.insert(db.getSession(), userDto); | |||
db.getSession().commit(); | |||
UserDto user = underTest.selectActiveUserByLogin(db.getSession(), "john"); | |||
verify(auditPersister).addUser(eq(db.getSession()), newValueCaptor.capture()); | |||
UserNewValue newValue = newValueCaptor.getValue(); | |||
assertThat(newValue) | |||
.extracting(UserNewValue::getUserUuid, UserNewValue::getLogin) | |||
.containsExactly(user.getUuid(), user.getLogin()); | |||
assertThat(newValue.toString()).doesNotContain("'name':"); | |||
} | |||
@Test | |||
public void update_user() { | |||
UserDto user = db.users().insertUser(u -> u | |||
.setLogin("john") | |||
.setName("John") | |||
.setEmail("jo@hn.com") | |||
.setActive(true) | |||
.setLocal(true) | |||
.setOnboarded(false) | |||
.setResetPassword(false)); | |||
UserDto updatedUser = newUserDto() | |||
.setUuid(user.getUuid()) | |||
.setLogin("johnDoo") | |||
.setName("John Doo") | |||
.setEmail("jodoo@hn.com") | |||
.setScmAccounts(",jo.hn,john2,johndoo,") | |||
.setActive(false) | |||
.setOnboarded(true) | |||
.setResetPassword(true) | |||
.setSalt("12345") | |||
.setCryptedPassword("abcde") | |||
.setHashMethod("BCRYPT") | |||
.setExternalLogin("johngithub") | |||
.setExternalIdentityProvider("github") | |||
.setExternalId("EXT_ID") | |||
.setLocal(false) | |||
.setHomepageType("project") | |||
.setHomepageParameter("OB1") | |||
.setLastConnectionDate(10_000_000_000L); | |||
underTest.update(db.getSession(), updatedUser); | |||
verify(auditPersister).updateUser(eq(db.getSession()), newValueCaptor.capture()); | |||
UserNewValue newValue = newValueCaptor.getValue(); | |||
assertThat(newValue) | |||
.extracting(UserNewValue::getUserUuid, UserNewValue::getLogin, UserNewValue::getName, UserNewValue::getEmail, UserNewValue::isActive, | |||
UserNewValue::getScmAccounts, UserNewValue::getExternalId, UserNewValue::getExternalLogin, UserNewValue::getExternalIdentityProvider, | |||
UserNewValue::isLocal, UserNewValue::isOnboarded, UserNewValue::isRoot, UserNewValue::getLastConnectionDate) | |||
.containsExactly(updatedUser.getUuid(), updatedUser.getLogin(), updatedUser.getName(), updatedUser.getEmail(), updatedUser.isActive(), | |||
updatedUser.getScmAccounts(), updatedUser.getExternalId(), updatedUser.getExternalLogin(), updatedUser.getExternalIdentityProvider(), | |||
updatedUser.isLocal(), updatedUser.isOnboarded(), updatedUser.isRoot(), updatedUser.getLastConnectionDate()); | |||
assertThat(newValue.toString()).contains("'name':"); | |||
} | |||
@Test | |||
public void update_user_without_track() { | |||
UserDto user = db.users().insertUser(u -> u | |||
.setLogin("john") | |||
.setName("John") | |||
.setEmail("jo@hn.com") | |||
.setActive(true) | |||
.setLocal(true) | |||
.setOnboarded(false) | |||
.setResetPassword(false)); | |||
verify(auditPersister).addUser(eq(db.getSession()), newValueCaptor.capture()); | |||
UserDto updatedUser = newUserDto() | |||
.setUuid(user.getUuid()) | |||
.setLogin("johnDoo"); | |||
underTest.update(db.getSession(), updatedUser, false); | |||
verifyNoMoreInteractions(auditPersister); | |||
} | |||
@Test | |||
public void deactivate_user() { | |||
UserDto user = insertActiveUser(); | |||
insertUserGroup(user); | |||
underTest.update(db.getSession(), user.setLastConnectionDate(10_000_000_000L)); | |||
db.getSession().commit(); | |||
underTest.deactivateUser(db.getSession(), user); | |||
verify(auditPersister).deactivateUser(eq(db.getSession()), newValueCaptor.capture()); | |||
assertThat(newValueCaptor.getValue()) | |||
.extracting(UserNewValue::getUserUuid, UserNewValue::getLogin) | |||
.containsExactly(user.getUuid(), user.getLogin()); | |||
} | |||
private UserDto insertActiveUser() { | |||
UserDto dto = newUserDto().setActive(true); | |||
underTest.insert(db.getSession(), dto); | |||
return dto; | |||
} | |||
private UserGroupDto insertUserGroup(UserDto user) { | |||
GroupDto group = newGroupDto().setName(randomAlphanumeric(30)); | |||
dbClient.groupDao().insert(db.getSession(), group); | |||
UserGroupDto dto = new UserGroupDto().setUserUuid(user.getUuid()).setGroupUuid(group.getUuid()); | |||
dbClient.userGroupDao().insert(db.getSession(), dto, group.getName(), user.getLogin()); | |||
return dto; | |||
} | |||
} |
@@ -42,7 +42,7 @@ public class UserGroupDaoTest { | |||
GroupDto group = dbTester.users().insertGroup(); | |||
UserGroupDto userGroupDto = new UserGroupDto().setUserUuid(user.getUuid()).setGroupUuid(group.getUuid()); | |||
underTest.insert(dbTester.getSession(), userGroupDto); | |||
underTest.insert(dbTester.getSession(), userGroupDto, group.getName(), user.getLogin()); | |||
dbTester.getSession().commit(); | |||
assertThat(dbTester.getDbClient().groupMembershipDao().selectGroupUuidsByUserUuid(dbTester.getSession(), user.getUuid())).containsOnly(group.getUuid()); | |||
@@ -58,9 +58,9 @@ public class UserGroupDaoTest { | |||
UserGroupDto userGroupDto1 = new UserGroupDto().setUserUuid(user1.getUuid()).setGroupUuid(group1.getUuid()); | |||
UserGroupDto userGroupDto2 = new UserGroupDto().setUserUuid(user2.getUuid()).setGroupUuid(group2.getUuid()); | |||
UserGroupDto userGroupDto3 = new UserGroupDto().setUserUuid(user3.getUuid()).setGroupUuid(group2.getUuid()); | |||
underTest.insert(dbSession, userGroupDto1); | |||
underTest.insert(dbSession, userGroupDto2); | |||
underTest.insert(dbSession, userGroupDto3); | |||
underTest.insert(dbSession, userGroupDto1, group1.getName(), user1.getLogin()); | |||
underTest.insert(dbSession, userGroupDto2, group2.getName(), user2.getLogin()); | |||
underTest.insert(dbSession, userGroupDto3, group2.getName(), user3.getLogin()); | |||
dbTester.getSession().commit(); | |||
Set<String> userUuids = underTest.selectUserUuidsInGroup(dbTester.getSession(), group2.getUuid()); | |||
@@ -74,7 +74,7 @@ public class UserGroupDaoTest { | |||
GroupDto group1 = dbTester.users().insertGroup(); | |||
GroupDto group2 = dbTester.users().insertGroup(); | |||
UserGroupDto userGroupDto1 = new UserGroupDto().setUserUuid(user1.getUuid()).setGroupUuid(group1.getUuid()); | |||
underTest.insert(dbSession, userGroupDto1); | |||
underTest.insert(dbSession, userGroupDto1, group1.getName(), user1.getLogin()); | |||
dbTester.getSession().commit(); | |||
Set<String> userUuids = underTest.selectUserUuidsInGroup(dbTester.getSession(), group2.getUuid()); | |||
@@ -93,7 +93,7 @@ public class UserGroupDaoTest { | |||
dbTester.users().insertMember(group2, user1); | |||
dbTester.users().insertMember(group2, user2); | |||
underTest.deleteByGroupUuid(dbTester.getSession(), group1.getUuid()); | |||
underTest.deleteByGroupUuid(dbTester.getSession(), group1.getUuid(), group1.getName()); | |||
dbTester.getSession().commit(); | |||
assertThat(dbTester.getDbClient().groupMembershipDao().selectGroupUuidsByUserUuid(dbTester.getSession(), user1.getUuid())).containsOnly(group2.getUuid()); | |||
@@ -111,7 +111,7 @@ public class UserGroupDaoTest { | |||
dbTester.users().insertMember(group2, user1); | |||
dbTester.users().insertMember(group2, user2); | |||
underTest.deleteByUserUuid(dbTester.getSession(), user1.getUuid()); | |||
underTest.deleteByUserUuid(dbTester.getSession(), user1); | |||
dbTester.getSession().commit(); | |||
assertThat(dbTester.getDbClient().groupMembershipDao().selectGroupUuidsByUserUuid(dbTester.getSession(), user1.getUuid())).isEmpty(); |
@@ -0,0 +1,125 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.user; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.mockito.ArgumentCaptor; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.audit.AuditPersister; | |||
import org.sonar.db.audit.model.UserGroupNewValue; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.ArgumentMatchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
public class UserGroupDaoWithPersisterTest { | |||
private final AuditPersister auditPersister = mock(AuditPersister.class); | |||
@Rule | |||
public final DbTester db = DbTester.create(System2.INSTANCE, auditPersister); | |||
private final ArgumentCaptor<UserGroupNewValue> newValueCaptor = ArgumentCaptor.forClass(UserGroupNewValue.class); | |||
private final DbClient dbClient = db.getDbClient(); | |||
private final UserGroupDao underTest = dbClient.userGroupDao(); | |||
@Test | |||
public void insert() { | |||
UserDto user = db.users().insertUser(); | |||
verify(auditPersister).addUser(eq(db.getSession()), any()); | |||
GroupDto group = db.users().insertGroup(); | |||
UserGroupDto userGroupDto = new UserGroupDto().setUserUuid(user.getUuid()).setGroupUuid(group.getUuid()); | |||
underTest.insert(db.getSession(), userGroupDto, group.getName(), user.getLogin()); | |||
db.getSession().commit(); | |||
verify(auditPersister).addUserToGroup(eq(db.getSession()), newValueCaptor.capture()); | |||
assertThat(db.getDbClient().groupMembershipDao().selectGroupUuidsByUserUuid(db.getSession(), user.getUuid())).containsOnly(group.getUuid()); | |||
assertThat(newValueCaptor.getValue()) | |||
.extracting(UserGroupNewValue::getGroupUuid, UserGroupNewValue::getName, UserGroupNewValue::getUserUuid, UserGroupNewValue::getUserLogin) | |||
.containsExactly(group.getUuid(), group.getName(), user.getUuid(), user.getLogin()); | |||
} | |||
@Test | |||
public void delete_members_by_group_uuid() { | |||
UserDto user1 = db.users().insertUser(); | |||
UserDto user2 = db.users().insertUser(); | |||
GroupDto group1 = db.users().insertGroup(); | |||
GroupDto group2 = db.users().insertGroup(); | |||
db.users().insertMember(group1, user1); | |||
db.users().insertMember(group1, user2); | |||
db.users().insertMember(group2, user1); | |||
db.users().insertMember(group2, user2); | |||
underTest.deleteByGroupUuid(db.getSession(), group1.getUuid(), group1.getName()); | |||
db.getSession().commit(); | |||
assertThat(db.getDbClient().groupMembershipDao().selectGroupUuidsByUserUuid(db.getSession(), user1.getUuid())).containsOnly(group2.getUuid()); | |||
assertThat(db.getDbClient().groupMembershipDao().selectGroupUuidsByUserUuid(db.getSession(), user2.getUuid())).containsOnly(group2.getUuid()); | |||
verify(auditPersister).deleteUserFromGroup(eq(db.getSession()), newValueCaptor.capture()); | |||
assertThat(newValueCaptor.getValue()) | |||
.extracting(UserGroupNewValue::getGroupUuid, UserGroupNewValue::getName) | |||
.containsExactly(group1.getUuid(), group1.getName()); | |||
} | |||
@Test | |||
public void delete_by_user() { | |||
UserDto user1 = db.users().insertUser(); | |||
UserDto user2 = db.users().insertUser(); | |||
GroupDto group1 = db.users().insertGroup(); | |||
GroupDto group2 = db.users().insertGroup(); | |||
db.users().insertMember(group1, user1); | |||
db.users().insertMember(group1, user2); | |||
db.users().insertMember(group2, user1); | |||
db.users().insertMember(group2, user2); | |||
underTest.deleteByUserUuid(db.getSession(), user1); | |||
db.getSession().commit(); | |||
assertThat(db.getDbClient().groupMembershipDao().selectGroupUuidsByUserUuid(db.getSession(), user1.getUuid())).isEmpty(); | |||
assertThat(db.getDbClient().groupMembershipDao().selectGroupUuidsByUserUuid(db.getSession(), user2.getUuid())).containsOnly(group1.getUuid(), group2.getUuid()); | |||
verify(auditPersister).deleteUserFromGroup(eq(db.getSession()), newValueCaptor.capture()); | |||
assertThat(newValueCaptor.getValue()) | |||
.extracting(UserGroupNewValue::getUserUuid, UserGroupNewValue::getUserLogin) | |||
.containsExactly(user1.getUuid(), user1.getLogin()); | |||
} | |||
@Test | |||
public void delete_by_user_and_group() { | |||
UserDto user1 = db.users().insertUser(); | |||
UserDto user2 = db.users().insertUser(); | |||
GroupDto group1 = db.users().insertGroup(); | |||
db.users().insertMember(group1, user1); | |||
db.users().insertMember(group1, user2); | |||
underTest.delete(db.getSession(), group1, user1); | |||
db.getSession().commit(); | |||
assertThat(db.getDbClient().groupMembershipDao().selectGroupUuidsByUserUuid(db.getSession(), user1.getUuid())).isEmpty(); | |||
assertThat(db.getDbClient().groupMembershipDao().selectGroupUuidsByUserUuid(db.getSession(), user2.getUuid())).containsOnly(group1.getUuid()); | |||
verify(auditPersister).deleteUserFromGroup(eq(db.getSession()), newValueCaptor.capture()); | |||
assertThat(newValueCaptor.getValue()) | |||
.extracting(UserGroupNewValue::getGroupUuid, UserGroupNewValue::getName, UserGroupNewValue::getUserUuid, UserGroupNewValue::getUserLogin) | |||
.containsExactly(group1.getUuid(), group1.getName(), user1.getUuid(), user1.getLogin()); | |||
} | |||
} |
@@ -61,9 +61,10 @@ public class UserPropertiesDaoTest { | |||
UserDto user = db.users().insertUser(); | |||
UserPropertyDto userSetting = underTest.insertOrUpdate(db.getSession(), new UserPropertyDto() | |||
.setUserUuid(user.getUuid()) | |||
.setKey("a_key") | |||
.setValue("a_value")); | |||
.setUserUuid(user.getUuid()) | |||
.setKey("a_key") | |||
.setValue("a_value"), | |||
user.getLogin()); | |||
Map<String, Object> map = db.selectFirst(db.getSession(), "select uuid as \"uuid\",\n" + | |||
" user_uuid as \"userUuid\",\n" + | |||
@@ -85,15 +86,17 @@ public class UserPropertiesDaoTest { | |||
public void update() { | |||
UserDto user = db.users().insertUser(); | |||
UserPropertyDto userProperty = underTest.insertOrUpdate(db.getSession(), new UserPropertyDto() | |||
.setUserUuid(user.getUuid()) | |||
.setKey("a_key") | |||
.setValue("old_value")); | |||
.setUserUuid(user.getUuid()) | |||
.setKey("a_key") | |||
.setValue("old_value"), | |||
user.getLogin()); | |||
system2.setNow(2_000_000_000_000L); | |||
underTest.insertOrUpdate(db.getSession(), new UserPropertyDto() | |||
.setUserUuid(user.getUuid()) | |||
.setKey("a_key") | |||
.setValue("new_value")); | |||
.setUserUuid(user.getUuid()) | |||
.setKey("a_key") | |||
.setValue("new_value"), | |||
user.getLogin()); | |||
Map<String, Object> map = db.selectFirst(db.getSession(), "select uuid as \"uuid\",\n" + | |||
" user_uuid as \"userUuid\",\n" + |
@@ -0,0 +1,173 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.user; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.mockito.ArgumentCaptor; | |||
import org.sonar.api.impl.utils.TestSystem2; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.audit.AuditPersister; | |||
import org.sonar.db.audit.model.PropertyNewValue; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.ArgumentMatchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.times; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.verifyNoMoreInteractions; | |||
import static org.mockito.Mockito.when; | |||
public class UserPropertiesDaoWithPersisterTest { | |||
private static final long NOW = 1_500_000_000_000L; | |||
private static final String SECURED_PROPERTY_KEY = "a_key.secured"; | |||
private static final String PROPERTY_KEY = "a_key"; | |||
private final AuditPersister auditPersister = mock(AuditPersister.class); | |||
private ArgumentCaptor<PropertyNewValue> newValueCaptor = ArgumentCaptor.forClass(PropertyNewValue.class); | |||
private TestSystem2 system2 = new TestSystem2().setNow(NOW); | |||
@Rule | |||
public DbTester db = DbTester.create(system2, auditPersister); | |||
private UserPropertiesDao underTest = db.getDbClient().userPropertiesDao(); | |||
@Test | |||
public void insert_tracked_property() { | |||
when(auditPersister.isTrackedProperty(PROPERTY_KEY)).thenReturn(true); | |||
UserDto user = db.users().insertUser(); | |||
verify(auditPersister).addUser(eq(db.getSession()), any()); | |||
UserPropertyDto userSetting = underTest.insertOrUpdate(db.getSession(), new UserPropertyDto() | |||
.setUserUuid(user.getUuid()) | |||
.setKey(PROPERTY_KEY) | |||
.setValue("a_value"), | |||
user.getLogin()); | |||
verify(auditPersister).addUserProperty(eq(db.getSession()), newValueCaptor.capture()); | |||
verify(auditPersister).isTrackedProperty(PROPERTY_KEY); | |||
assertThat(newValueCaptor.getValue()) | |||
.extracting(PropertyNewValue::getPropertyKey, PropertyNewValue::getPropertyValue, PropertyNewValue::getUserUuid, | |||
PropertyNewValue::getUserLogin) | |||
.containsExactly(userSetting.getKey(), userSetting.getValue(), user.getUuid(), user.getLogin()); | |||
} | |||
@Test | |||
public void insert_tracked_secured_property() { | |||
when(auditPersister.isTrackedProperty(SECURED_PROPERTY_KEY)).thenReturn(true); | |||
UserDto user = db.users().insertUser(); | |||
verify(auditPersister).addUser(eq(db.getSession()), any()); | |||
UserPropertyDto userSetting = underTest.insertOrUpdate(db.getSession(), new UserPropertyDto() | |||
.setUserUuid(user.getUuid()) | |||
.setKey(SECURED_PROPERTY_KEY) | |||
.setValue("a_value"), | |||
user.getLogin()); | |||
verify(auditPersister).isTrackedProperty(SECURED_PROPERTY_KEY); | |||
verify(auditPersister).addUserProperty(eq(db.getSession()), newValueCaptor.capture()); | |||
PropertyNewValue newValue = newValueCaptor.getValue(); | |||
assertThat(newValue) | |||
.extracting(PropertyNewValue::getPropertyKey, PropertyNewValue::getPropertyValue, PropertyNewValue::getUserUuid, | |||
PropertyNewValue::getUserLogin) | |||
.containsExactly(userSetting.getKey(), null, user.getUuid(), user.getLogin()); | |||
assertThat(newValue.toString()).doesNotContain("'propertyValue':"); | |||
} | |||
@Test | |||
public void insert_not_tracked_property() { | |||
when(auditPersister.isTrackedProperty(PROPERTY_KEY)).thenReturn(false); | |||
UserDto user = db.users().insertUser(); | |||
underTest.insertOrUpdate(db.getSession(), new UserPropertyDto() | |||
.setUserUuid(user.getUuid()) | |||
.setKey(PROPERTY_KEY) | |||
.setValue("a_value"), | |||
user.getLogin()); | |||
verify(auditPersister).addUser(eq(db.getSession()), any()); | |||
verify(auditPersister).isTrackedProperty(PROPERTY_KEY); | |||
verifyNoMoreInteractions(auditPersister); | |||
} | |||
@Test | |||
public void update() { | |||
when(auditPersister.isTrackedProperty(PROPERTY_KEY)).thenReturn(true); | |||
UserDto user = db.users().insertUser(); | |||
underTest.insertOrUpdate(db.getSession(), new UserPropertyDto() | |||
.setUserUuid(user.getUuid()) | |||
.setKey(PROPERTY_KEY) | |||
.setValue("old_value"), | |||
user.getLogin()); | |||
system2.setNow(2_000_000_000_000L); | |||
UserPropertyDto userSetting = underTest.insertOrUpdate(db.getSession(), new UserPropertyDto() | |||
.setUserUuid(user.getUuid()) | |||
.setKey(PROPERTY_KEY) | |||
.setValue("new_value"), | |||
user.getLogin()); | |||
verify(auditPersister).addUser(eq(db.getSession()), any()); | |||
verify(auditPersister).addUserProperty(eq(db.getSession()), any()); | |||
verify(auditPersister).updateUserProperty(eq(db.getSession()), newValueCaptor.capture()); | |||
assertThat(newValueCaptor.getValue()) | |||
.extracting(PropertyNewValue::getPropertyKey, PropertyNewValue::getPropertyValue, PropertyNewValue::getUserUuid, | |||
PropertyNewValue::getUserLogin) | |||
.containsExactly(userSetting.getKey(), userSetting.getValue(), user.getUuid(), user.getLogin()); | |||
} | |||
@Test | |||
public void delete_by_user() { | |||
when(auditPersister.isTrackedProperty(PROPERTY_KEY)).thenReturn(true); | |||
when(auditPersister.isTrackedProperty(SECURED_PROPERTY_KEY)).thenReturn(false); | |||
UserDto user = db.users().insertUser(); | |||
UserPropertyDto userSetting = underTest.insertOrUpdate(db.getSession(), new UserPropertyDto() | |||
.setUserUuid(user.getUuid()) | |||
.setKey(PROPERTY_KEY) | |||
.setValue("a_value"), | |||
user.getLogin()); | |||
underTest.insertOrUpdate(db.getSession(), new UserPropertyDto() | |||
.setUserUuid(user.getUuid()) | |||
.setKey(SECURED_PROPERTY_KEY) | |||
.setValue("another_value"), | |||
user.getLogin()); | |||
underTest.deleteByUser(db.getSession(), user); | |||
verify(auditPersister).addUser(eq(db.getSession()), any()); | |||
verify(auditPersister).addUserProperty(eq(db.getSession()), any()); | |||
verify(auditPersister).addUserProperty(eq(db.getSession()), any()); | |||
verify(auditPersister, times(2)).isTrackedProperty(PROPERTY_KEY); | |||
verify(auditPersister, times(2)).isTrackedProperty(SECURED_PROPERTY_KEY); | |||
verify(auditPersister).deleteUserProperty(eq(db.getSession()), newValueCaptor.capture()); | |||
verifyNoMoreInteractions(auditPersister); | |||
assertThat(newValueCaptor.getValue()) | |||
.extracting(PropertyNewValue::getPropertyKey, PropertyNewValue::getPropertyValue, PropertyNewValue::getUserUuid, | |||
PropertyNewValue::getUserLogin) | |||
.containsExactly(userSetting.getKey(), userSetting.getValue(), user.getUuid(), user.getLogin()); | |||
} | |||
} |
@@ -45,7 +45,7 @@ public class UserTokenDaoTest { | |||
public void insert_token() { | |||
UserTokenDto userToken = newUserToken(); | |||
underTest.insert(db.getSession(), userToken); | |||
underTest.insert(db.getSession(), userToken, "login"); | |||
UserTokenDto userTokenFromDb = underTest.selectByTokenHash(db.getSession(), userToken.getTokenHash()); | |||
assertThat(userTokenFromDb).isNotNull(); | |||
@@ -63,7 +63,7 @@ public class UserTokenDaoTest { | |||
UserTokenDto userToken2 = db.users().insertToken(user1); | |||
assertThat(underTest.selectByTokenHash(dbSession, userToken1.getTokenHash()).getLastConnectionDate()).isNull(); | |||
underTest.update(dbSession, userToken1.setLastConnectionDate(10_000_000_000L)); | |||
underTest.update(dbSession, userToken1.setLastConnectionDate(10_000_000_000L), false, null); | |||
UserTokenDto userTokenReloaded = underTest.selectByTokenHash(dbSession, userToken1.getTokenHash()); | |||
assertThat(userTokenReloaded.getLastConnectionDate()).isEqualTo(10_000_000_000L); |
@@ -0,0 +1,123 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.user; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.mockito.ArgumentCaptor; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.audit.AuditPersister; | |||
import org.sonar.db.audit.model.UserTokenNewValue; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.ArgumentMatchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.sonar.db.user.UserTokenTesting.newUserToken; | |||
public class UserTokenDaoWithPersisterTest { | |||
private final AuditPersister auditPersister = mock(AuditPersister.class); | |||
private final ArgumentCaptor<UserTokenNewValue> newValueCaptor = ArgumentCaptor.forClass(UserTokenNewValue.class); | |||
@Rule | |||
public final DbTester db = DbTester.create(System2.INSTANCE, auditPersister); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
private final DbSession dbSession = db.getSession(); | |||
private final DbClient dbClient = db.getDbClient(); | |||
private final UserTokenDao underTest = dbClient.userTokenDao(); | |||
@Test | |||
public void insert_token() { | |||
UserTokenDto userToken = newUserToken(); | |||
underTest.insert(db.getSession(), userToken, "login"); | |||
verify(auditPersister).addUserToken(eq(db.getSession()), newValueCaptor.capture()); | |||
UserTokenDto userTokenFromDb = underTest.selectByTokenHash(db.getSession(), userToken.getTokenHash()); | |||
assertThat(userTokenFromDb).isNotNull(); | |||
assertThat(userTokenFromDb.getUuid()).isEqualTo(userToken.getUuid()); | |||
assertThat(userTokenFromDb.getName()).isEqualTo(userToken.getName()); | |||
assertThat(userTokenFromDb.getCreatedAt()).isEqualTo(userToken.getCreatedAt()); | |||
assertThat(userTokenFromDb.getTokenHash()).isEqualTo(userToken.getTokenHash()); | |||
assertThat(userTokenFromDb.getUserUuid()).isEqualTo(userToken.getUserUuid()); | |||
UserTokenNewValue newValue = newValueCaptor.getValue(); | |||
assertThat(newValue) | |||
.extracting(UserTokenNewValue::getTokenUuid, UserTokenNewValue::getTokenName, UserTokenNewValue::getUserUuid, UserTokenNewValue::getLastConnectionDate) | |||
.containsExactly(userToken.getUuid(), userToken.getName(), userToken.getUserUuid(), userToken.getLastConnectionDate()); | |||
assertThat(newValue.toString()).contains("'tokenUuid':"); | |||
} | |||
@Test | |||
public void update_token() { | |||
UserDto user1 = db.users().insertUser(); | |||
UserTokenDto userToken1 = db.users().insertToken(user1); | |||
assertThat(underTest.selectByTokenHash(dbSession, userToken1.getTokenHash()).getLastConnectionDate()).isNull(); | |||
underTest.update(dbSession, userToken1.setLastConnectionDate(10_000_000_000L), false, null); | |||
underTest.update(dbSession, userToken1.setName("new_name"), user1.getLogin()); | |||
verify(auditPersister).updateUserToken(eq(db.getSession()), newValueCaptor.capture()); | |||
assertThat(newValueCaptor.getValue()) | |||
.extracting(UserTokenNewValue::getTokenUuid, UserTokenNewValue::getTokenName, UserTokenNewValue::getUserUuid, UserTokenNewValue::getLastConnectionDate) | |||
.containsExactly(userToken1.getUuid(), "new_name", userToken1.getUserUuid(), userToken1.getLastConnectionDate()); | |||
} | |||
@Test | |||
public void delete_tokens_by_user() { | |||
UserDto user1 = db.users().insertUser(); | |||
UserDto user2 = db.users().insertUser(); | |||
db.users().insertToken(user1); | |||
db.users().insertToken(user1); | |||
db.users().insertToken(user2); | |||
underTest.deleteByUser(dbSession, user1); | |||
db.commit(); | |||
assertThat(underTest.selectByUser(dbSession, user1)).isEmpty(); | |||
assertThat(underTest.selectByUser(dbSession, user2)).hasSize(1); | |||
verify(auditPersister).deleteUserToken(eq(db.getSession()), newValueCaptor.capture()); | |||
assertThat(newValueCaptor.getValue()) | |||
.extracting(UserTokenNewValue::getUserUuid, UserTokenNewValue::getUserLogin) | |||
.containsExactly(user1.getUuid(), user1.getLogin()); | |||
} | |||
@Test | |||
public void delete_token_by_user_and_name() { | |||
UserDto user1 = db.users().insertUser(); | |||
UserDto user2 = db.users().insertUser(); | |||
db.users().insertToken(user1, t -> t.setName("name")); | |||
db.users().insertToken(user1, t -> t.setName("another-name")); | |||
db.users().insertToken(user2, t -> t.setName("name")); | |||
underTest.deleteByUserAndName(dbSession, user1, "name"); | |||
assertThat(underTest.selectByUserAndName(dbSession, user1, "name")).isNull(); | |||
assertThat(underTest.selectByUserAndName(dbSession, user1, "another-name")).isNotNull(); | |||
assertThat(underTest.selectByUserAndName(dbSession, user2, "name")).isNotNull(); | |||
verify(auditPersister).deleteUserToken(eq(db.getSession()), newValueCaptor.capture()); | |||
assertThat(newValueCaptor.getValue()) | |||
.extracting(UserTokenNewValue::getUserUuid, UserTokenNewValue::getUserLogin, UserTokenNewValue::getTokenName) | |||
.containsExactly(user1.getUuid(), user1.getLogin(), "name"); | |||
} | |||
} |
@@ -34,6 +34,7 @@ import org.sonar.core.util.SequenceUuidFactory; | |||
import org.sonar.core.util.UuidFactory; | |||
import org.sonar.db.alm.integration.pat.AlmPatsDbTester; | |||
import org.sonar.db.almsettings.AlmSettingsDbTester; | |||
import org.sonar.db.audit.AuditPersister; | |||
import org.sonar.db.component.ComponentDbTester; | |||
import org.sonar.db.component.ProjectLinkDbTester; | |||
import org.sonar.db.event.EventDbTester; | |||
@@ -88,11 +89,11 @@ public class DbTester extends AbstractDbTester<TestDbImpl> { | |||
private final AlmSettingsDbTester almSettingsDbTester; | |||
private final AlmPatsDbTester almPatsDbtester; | |||
private DbTester(System2 system2, @Nullable String schemaPath, MyBatisConfExtension... confExtensions) { | |||
private DbTester(System2 system2, @Nullable String schemaPath, AuditPersister auditPersister, MyBatisConfExtension... confExtensions) { | |||
super(TestDbImpl.create(schemaPath, confExtensions)); | |||
this.system2 = system2; | |||
initDbClient(); | |||
initDbClient(auditPersister); | |||
this.userTester = new UserDbTester(this); | |||
this.componentTester = new ComponentDbTester(this); | |||
this.componentLinkTester = new ProjectLinkDbTester(this); | |||
@@ -118,19 +119,26 @@ public class DbTester extends AbstractDbTester<TestDbImpl> { | |||
} | |||
public static DbTester create() { | |||
return new DbTester(System2.INSTANCE, null); | |||
return new DbTester(System2.INSTANCE, null, null); | |||
} | |||
public static DbTester create(System2 system2, AuditPersister auditPersister) { | |||
return new DbTester(system2, null, auditPersister); | |||
} | |||
public static DbTester create(System2 system2) { | |||
return new DbTester(system2, null); | |||
return new DbTester(system2, null, null); | |||
} | |||
public static DbTester createWithExtensionMappers(System2 system2, Class<?> firstMapperClass, Class<?>... otherMapperClasses) { | |||
return new DbTester(system2, null, new DbTesterMyBatisConfExtension(firstMapperClass, otherMapperClasses)); | |||
return new DbTester(system2, null, null, new DbTesterMyBatisConfExtension(firstMapperClass, otherMapperClasses)); | |||
} | |||
private void initDbClient() { | |||
private void initDbClient(AuditPersister auditPersister) { | |||
TransientPicoContainer ioc = new TransientPicoContainer(); | |||
if (auditPersister != null) { | |||
ioc.addComponent(auditPersister); | |||
} | |||
ioc.addComponent(db.getMyBatis()); | |||
ioc.addComponent(system2); | |||
ioc.addComponent(uuidFactory); | |||
@@ -145,7 +153,7 @@ public class DbTester extends AbstractDbTester<TestDbImpl> { | |||
protected void before() { | |||
db.start(); | |||
db.truncateTables(); | |||
initDbClient(); | |||
initDbClient(null); | |||
} | |||
public UserDbTester users() { |
@@ -0,0 +1,41 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.db.audit; | |||
import java.util.Random; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | |||
public class AuditTesting { | |||
private static final Random random = new Random(); | |||
public static AuditDto newAuditDto() { | |||
AuditDto auditDto = new AuditDto(); | |||
auditDto.setUuid(randomAlphanumeric(20)); | |||
auditDto.setUserUuid(randomAlphanumeric(40)); | |||
auditDto.setUserLogin(randomAlphanumeric(40)); | |||
auditDto.setNewValue(randomAlphanumeric(2000)); | |||
auditDto.setOperation("operation"); | |||
auditDto.setCategory("category"); | |||
auditDto.setCreatedAt(random.nextLong()); | |||
return auditDto; | |||
} | |||
} |
@@ -134,7 +134,7 @@ public class UserDbTester { | |||
public final UserPropertyDto insertUserSetting(UserDto user, Consumer<UserPropertyDto>... populators) { | |||
UserPropertyDto dto = UserTesting.newUserSettingDto(user); | |||
stream(populators).forEach(p -> p.accept(dto)); | |||
dbClient.userPropertiesDao().insertOrUpdate(db.getSession(), dto); | |||
dbClient.userPropertiesDao().insertOrUpdate(db.getSession(), dto, user.getLogin()); | |||
db.commit(); | |||
return dto; | |||
} | |||
@@ -176,7 +176,7 @@ public class UserDbTester { | |||
public UserGroupDto insertMember(GroupDto group, UserDto user) { | |||
UserGroupDto dto = new UserGroupDto().setGroupUuid(group.getUuid()).setUserUuid(user.getUuid()); | |||
db.getDbClient().userGroupDao().insert(db.getSession(), dto); | |||
db.getDbClient().userGroupDao().insert(db.getSession(), dto, group.getName(), user.getLogin()); | |||
db.commit(); | |||
return dto; | |||
} | |||
@@ -184,7 +184,7 @@ public class UserDbTester { | |||
public void insertMembers(GroupDto group, UserDto... users) { | |||
Arrays.stream(users).forEach(user -> { | |||
UserGroupDto dto = new UserGroupDto().setGroupUuid(group.getUuid()).setUserUuid(user.getUuid()); | |||
db.getDbClient().userGroupDao().insert(db.getSession(), dto); | |||
db.getDbClient().userGroupDao().insert(db.getSession(), dto, group.getName(), user.getLogin()); | |||
}); | |||
db.commit(); | |||
} | |||
@@ -342,7 +342,7 @@ public class UserDbTester { | |||
public final UserTokenDto insertToken(UserDto user, Consumer<UserTokenDto>... populators) { | |||
UserTokenDto dto = UserTokenTesting.newUserToken().setUserUuid(user.getUuid()); | |||
stream(populators).forEach(p -> p.accept(dto)); | |||
db.getDbClient().userTokenDao().insert(db.getSession(), dto); | |||
db.getDbClient().userTokenDao().insert(db.getSession(), dto, user.getLogin()); | |||
db.commit(); | |||
return dto; | |||
} |
@@ -0,0 +1,73 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.platform.db.migration.version.v91; | |||
import org.sonar.db.Database; | |||
import org.sonar.server.platform.db.migration.def.BigIntegerColumnDef; | |||
import org.sonar.server.platform.db.migration.def.ColumnDef; | |||
import org.sonar.server.platform.db.migration.def.VarcharColumnDef; | |||
import org.sonar.server.platform.db.migration.sql.CreateIndexBuilder; | |||
import org.sonar.server.platform.db.migration.sql.CreateTableBuilder; | |||
import org.sonar.server.platform.db.migration.step.DdlChange; | |||
import static java.util.Arrays.stream; | |||
import static java.util.stream.Stream.concat; | |||
import static java.util.stream.Stream.of; | |||
import static org.sonar.server.platform.db.migration.def.BigIntegerColumnDef.newBigIntegerColumnDefBuilder; | |||
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.UUID_SIZE; | |||
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; | |||
import java.sql.SQLException; | |||
public class CreateAuditTable extends DdlChange { | |||
public CreateAuditTable(Database db) { | |||
super(db); | |||
} | |||
@Override | |||
public void execute(Context context) throws SQLException { | |||
BigIntegerColumnDef createdAtColumn = newBigIntegerColumnDefBuilder().setColumnName("created_at").setIsNullable(false).build(); | |||
var tableName = "audits"; | |||
context.execute(new CreateTableBuilder(getDialect(), tableName) | |||
.addPkColumn(newVarcharColumnDefBuilder().setColumnName("uuid").setIsNullable(false).setLimit(UUID_SIZE).build()) | |||
.addColumn(newVarcharColumnBuilder("user_uuid").setIsNullable(false).setLimit(UUID_SIZE).build()) | |||
.addColumn(newVarcharColumnBuilder("user_login").setIsNullable(false).setLimit(255).build()) | |||
.addColumn(newVarcharColumnBuilder("category").setIsNullable(false).setLimit(20).build()) | |||
.addColumn(newVarcharColumnBuilder("operation").setIsNullable(false).setLimit(50).build()) | |||
.addColumn(newVarcharColumnBuilder("new_value").setIsNullable(true).setLimit(4000).build()) | |||
.addColumn(createdAtColumn) | |||
.build()); | |||
addIndex(context, tableName, "audits_created_at", false, createdAtColumn); | |||
} | |||
private static void addIndex(Context context, String table, String index, boolean unique, ColumnDef firstColumn, ColumnDef... otherColumns) { | |||
CreateIndexBuilder builder = new CreateIndexBuilder() | |||
.setTable(table) | |||
.setName(index) | |||
.setUnique(unique); | |||
concat(of(firstColumn), stream(otherColumns)).forEach(builder::addColumn); | |||
context.execute(builder.build()); | |||
} | |||
private static VarcharColumnDef.Builder newVarcharColumnBuilder(String column) { | |||
return newVarcharColumnDefBuilder().setColumnName(column); | |||
} | |||
} |
@@ -31,6 +31,7 @@ public class DbVersion91 implements DbVersion { | |||
.add(6003, "Drop custom metrics data from 'live_measures' table", DropCustomMetricsLiveMeasuresData.class) | |||
.add(6004, "Drop custom metrics data from 'project_measures' table", DropCustomMetricsProjectMeasuresData.class) | |||
.add(6005, "Drop custom metrics data from 'metrics' table", DropUserManagedMetricsData.class) | |||
.add(6006, "Drop 'user_managed' column from 'metrics' table", DropUserManagedColumnFromMetricsTable.class); | |||
.add(6006, "Drop 'user_managed' column from 'metrics' table", DropUserManagedColumnFromMetricsTable.class) | |||
.add(6007, "Create Audit table", CreateAuditTable.class); | |||
} | |||
} |
@@ -0,0 +1,45 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.platform.db.migration.version.v91; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.db.CoreDbTester; | |||
import java.sql.SQLException; | |||
public class CreateAuditTableTest { | |||
private static final String TABLE_NAME = "audits"; | |||
@Rule | |||
public final CoreDbTester db = CoreDbTester.createForSchema(CreateAuditTableTest.class, "schema.sql"); | |||
private final CreateAuditTable underTest = new CreateAuditTable(db.database()); | |||
@Test | |||
public void migration_should_create_a_table_with_index() throws SQLException { | |||
db.assertTableDoesNotExist(TABLE_NAME); | |||
underTest.execute(); | |||
db.assertTableExists(TABLE_NAME); | |||
db.assertIndex(TABLE_NAME, "audits_created_at", "created_at"); | |||
} | |||
} |
@@ -41,7 +41,7 @@ public class DbVersion91Test { | |||
@Test | |||
public void verify_migration_count() { | |||
verifyMigrationCount(underTest, 6); | |||
verifyMigrationCount(underTest, 7); | |||
} | |||
} |
@@ -0,0 +1 @@ | |||
DROP TABLE IF EXISTS AUDITS; |
@@ -46,7 +46,7 @@ public class UserLastConnectionDatesUpdaterImpl implements UserLastConnectionDat | |||
return; | |||
} | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
dbClient.userDao().update(dbSession, user.setLastConnectionDate(now)); | |||
dbClient.userDao().update(dbSession, user.setLastConnectionDate(now), false); | |||
dbSession.commit(); | |||
} | |||
} | |||
@@ -59,7 +59,7 @@ public class UserLastConnectionDatesUpdaterImpl implements UserLastConnectionDat | |||
return; | |||
} | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
dbClient.userTokenDao().update(dbSession, userToken.setLastConnectionDate(now)); | |||
dbClient.userTokenDao().update(dbSession, userToken.setLastConnectionDate(now), false, null); | |||
userToken.setLastConnectionDate(now); | |||
dbSession.commit(); | |||
} |
@@ -216,7 +216,8 @@ public class UserRegistrarImpl implements UserRegistrar { | |||
groupsToAdd.stream().map(groupsByName::get).filter(Objects::nonNull).forEach( | |||
groupDto -> { | |||
LOGGER.debug("Adding group '{}' to user '{}'", groupDto.getName(), userDto.getLogin()); | |||
dbClient.userGroupDao().insert(dbSession, new UserGroupDto().setGroupUuid(groupDto.getUuid()).setUserUuid(userDto.getUuid())); | |||
dbClient.userGroupDao().insert(dbSession, new UserGroupDto().setGroupUuid(groupDto.getUuid()).setUserUuid(userDto.getUuid()), | |||
groupDto.getName(), userDto.getLogin()); | |||
}); | |||
} | |||
@@ -229,7 +230,7 @@ public class UserRegistrarImpl implements UserRegistrar { | |||
.filter(group -> !defaultGroup.isPresent() || !group.getUuid().equals(defaultGroup.get().getUuid())) | |||
.forEach(groupDto -> { | |||
LOGGER.debug("Removing group '{}' from user '{}'", groupDto.getName(), userDto.getLogin()); | |||
dbClient.userGroupDao().delete(dbSession, groupDto.getUuid(), userDto.getUuid()); | |||
dbClient.userGroupDao().delete(dbSession, groupDto, userDto); | |||
}); | |||
} | |||
@@ -442,6 +442,7 @@ public class UserUpdater { | |||
if (isUserAlreadyMemberOfDefaultGroup(defaultGroup, userGroups)) { | |||
return; | |||
} | |||
dbClient.userGroupDao().insert(dbSession, new UserGroupDto().setUserUuid(userDto.getUuid()).setGroupUuid(defaultGroup.getUuid())); | |||
dbClient.userGroupDao().insert(dbSession, new UserGroupDto().setUserUuid(userDto.getUuid()).setGroupUuid(defaultGroup.getUuid()), | |||
defaultGroup.getName(), userDto.getLogin()); | |||
} | |||
} |
@@ -79,7 +79,7 @@ public class UserLastConnectionDatesUpdaterImplTest { | |||
public void update_last_connection_date_from_user_token_when_last_connection_was_more_than_one_hour() { | |||
UserDto user = db.users().insertUser(); | |||
UserTokenDto userToken = db.users().insertToken(user); | |||
db.getDbClient().userTokenDao().update(db.getSession(), userToken.setLastConnectionDate(NOW - TWO_HOUR)); | |||
db.getDbClient().userTokenDao().update(db.getSession(), userToken.setLastConnectionDate(NOW - TWO_HOUR), false, null); | |||
db.commit(); | |||
underTest.updateLastConnectionDateIfNeeded(userToken); | |||
@@ -103,7 +103,7 @@ public class UserLastConnectionDatesUpdaterImplTest { | |||
public void do_not_update_when_last_connection_from_user_token_was_less_than_one_hour() { | |||
UserDto user = db.users().insertUser(); | |||
UserTokenDto userToken = db.users().insertToken(user); | |||
db.getDbClient().userTokenDao().update(db.getSession(), userToken.setLastConnectionDate(NOW - ONE_MINUTE)); | |||
db.getDbClient().userTokenDao().update(db.getSession(), userToken.setLastConnectionDate(NOW - ONE_MINUTE), false, null); | |||
db.commit(); | |||
underTest.updateLastConnectionDateIfNeeded(userToken); |
@@ -58,7 +58,7 @@ public class DefaultGroupFinderTest { | |||
@Test | |||
public void fail_with_ISE_when_default_group_does_not_exist() { | |||
GroupDto defaultGroup = db.users().insertDefaultGroup(); | |||
db.getDbClient().groupDao().deleteByUuid(db.getSession(), defaultGroup.getUuid()); | |||
db.getDbClient().groupDao().deleteByUuid(db.getSession(), defaultGroup.getUuid(), defaultGroup.getName()); | |||
DbSession session = db.getSession(); | |||
assertThatThrownBy(() -> underTest.findDefaultGroup(session)) |
@@ -88,7 +88,7 @@ public class DeactivateAction implements UsersWsAction { | |||
dbClient.userTokenDao().deleteByUser(dbSession, user); | |||
dbClient.propertiesDao().deleteByKeyAndValue(dbSession, DEFAULT_ISSUE_ASSIGNEE, user.getLogin()); | |||
dbClient.propertiesDao().deleteByQuery(dbSession, PropertyQuery.builder().setUserUuid(userUuid).build()); | |||
dbClient.userGroupDao().deleteByUserUuid(dbSession, userUuid); | |||
dbClient.userGroupDao().deleteByUserUuid(dbSession, user); | |||
dbClient.userPermissionDao().deleteByUserUuid(dbSession, userUuid); | |||
dbClient.permissionTemplateDao().deleteUserPermissionsByUserUuid(dbSession, userUuid); | |||
dbClient.qProfileEditUsersDao().deleteByUser(dbSession, user); |
@@ -82,7 +82,8 @@ public class SetSettingAction implements UsersWsAction { | |||
new UserPropertyDto() | |||
.setUserUuid(requireNonNull(userSession.getUuid(), "Authenticated user uuid cannot be null")) | |||
.setKey(key) | |||
.setValue(value)); | |||
.setValue(value), | |||
userSession.getLogin()); | |||
dbSession.commit(); | |||
} | |||
} |
@@ -82,7 +82,7 @@ public class AddUserAction implements UserGroupsWsAction { | |||
if (!isMemberOf(dbSession, user, group)) { | |||
UserGroupDto membershipDto = new UserGroupDto().setGroupUuid(group.getUuid()).setUserUuid(user.getUuid()); | |||
dbClient.userGroupDao().insert(dbSession, membershipDto); | |||
dbClient.userGroupDao().insert(dbSession, membershipDto, group.getName(), login); | |||
dbSession.commit(); | |||
} | |||
@@ -76,7 +76,7 @@ public class DeleteAction implements UserGroupsWsAction { | |||
removeFromPermissionTemplates(dbSession, group); | |||
removeGroupMembers(dbSession, group); | |||
dbClient.qProfileEditGroupsDao().deleteByGroup(dbSession, group); | |||
dbClient.groupDao().deleteByUuid(dbSession, group.getUuid()); | |||
dbClient.groupDao().deleteByUuid(dbSession, group.getUuid(), group.getName()); | |||
dbSession.commit(); | |||
response.noContent(); | |||
@@ -99,6 +99,6 @@ public class DeleteAction implements UserGroupsWsAction { | |||
} | |||
private void removeGroupMembers(DbSession dbSession, GroupDto group) { | |||
dbClient.userGroupDao().deleteByGroupUuid(dbSession, group.getUuid()); | |||
dbClient.userGroupDao().deleteByGroupUuid(dbSession, group.getUuid(), group.getName()); | |||
} | |||
} |
@@ -83,7 +83,7 @@ public class RemoveUserAction implements UserGroupsWsAction { | |||
ensureLastAdminIsNotRemoved(dbSession, group, user); | |||
dbClient.userGroupDao().delete(dbSession, group.getUuid(), user.getUuid()); | |||
dbClient.userGroupDao().delete(dbSession, group, user); | |||
dbSession.commit(); | |||
response.noContent(); |
@@ -117,7 +117,7 @@ public class GenerateAction implements UserTokensWsAction { | |||
.setName(name) | |||
.setTokenHash(tokenHash) | |||
.setCreatedAt(system.now()); | |||
dbClient.userTokenDao().insert(dbSession, userTokenDto); | |||
dbClient.userTokenDao().insert(dbSession, userTokenDto, user.getLogin()); | |||
dbSession.commit(); | |||
return userTokenDto; | |||
} |
@@ -100,7 +100,7 @@ public class SearchActionTest { | |||
UserDto user = db.users().insertUser(); | |||
UserTokenDto token1 = db.users().insertToken(user); | |||
UserTokenDto token2 = db.users().insertToken(user); | |||
db.getDbClient().userTokenDao().update(db.getSession(), token1.setLastConnectionDate(10_000_000_000L)); | |||
db.getDbClient().userTokenDao().update(db.getSession(), token1.setLastConnectionDate(10_000_000_000L), false, user.getLogin()); | |||
db.commit(); | |||
logInAsSystemAdministrator(); | |||