org.graylog2.migrations.MigrationHelpers Maven / Gradle / Ivy
/*
* Copyright (C) 2020 Graylog, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* 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
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* .
*/
package org.graylog2.migrations;
import com.mongodb.DuplicateKeyException;
import jakarta.inject.Inject;
import org.graylog2.database.NotFoundException;
import org.graylog2.plugin.database.ValidationException;
import org.graylog2.plugin.database.users.User;
import org.graylog2.shared.users.Role;
import org.graylog2.shared.users.UserService;
import org.graylog2.users.RoleImpl;
import org.graylog2.users.RoleService;
import org.graylog2.users.UserServiceImpl;
import org.joda.time.DateTimeZone;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
public class MigrationHelpers {
private static final Logger LOG = LoggerFactory.getLogger(MigrationHelpers.class);
private final RoleService roleService;
private final UserService userService;
private final RoleRemover roleRemover;
@Inject
public MigrationHelpers(final RoleService roleService,
final UserService userService,
final RoleRemover roleRemover) {
this.roleService = roleService;
this.userService = userService;
this.roleRemover = roleRemover;
}
public void removeBuiltinRole(final String roleName) {
this.roleRemover.removeBuiltinRole(roleName);
}
@Nullable
public String ensureBuiltinRole(String roleName, String description, Set expectedPermissions) {
Role previousRole = null;
try {
previousRole = roleService.load(roleName);
if (!previousRole.isReadOnly() || !expectedPermissions.equals(previousRole.getPermissions())) {
final String msg = "Invalid role '" + roleName + "', fixing it.";
LOG.debug(msg);
throw new IllegalArgumentException(msg); // jump to fix code
}
} catch (NotFoundException | IllegalArgumentException | NoSuchElementException ignored) {
LOG.info("{} role is missing or invalid, re-adding it as a built-in role.", roleName);
final RoleImpl fixedRole = new RoleImpl();
// copy the mongodb id over, in order to update the role instead of reading it
if (previousRole != null) {
fixedRole._id = previousRole.getId();
}
fixedRole.setReadOnly(true);
fixedRole.setName(roleName);
fixedRole.setDescription(description);
fixedRole.setPermissions(expectedPermissions);
try {
final Role savedRole = roleService.save(fixedRole);
return savedRole.getId();
} catch (DuplicateKeyException | ValidationException e) {
LOG.error("Unable to save fixed '" + roleName + "' role, please restart Graylog to fix this.", e);
}
}
if (previousRole == null) {
LOG.error("Unable to access fixed '" + roleName + "' role, please restart Graylog to fix this.");
return null;
}
return previousRole.getId();
}
@Nullable
public String ensureUser(String userName, String password, String firstName, String lastName, String email,
Set expectedRoles) {
return ensureUser(userName, password, firstName, lastName, email, expectedRoles, false);
}
@Nullable
public String ensureUser(String userName, String password, String firstName, String lastName, String email,
Set expectedRoles, boolean isServiceAccount) {
try {
return ensureUserHelper(userName, password, firstName, lastName, email, expectedRoles, isServiceAccount);
} catch (UserServiceImpl.DuplicateUserException e) {
// Attempt to resolve simple duplication (introduced prior to adding the unique index).
// This does not account for special types of users, e.g. read-only users, imported users, etc.
final List users = userService.loadAllByName(userName);
User firstUser = users.remove(0);
for (User user : users) {
final String uniqueName = user.getName() + "_" + user.getId();
LOG.warn("Renaming duplicate users {} to {}", user.getName(), uniqueName);
user.setName(uniqueName);
try {
userService.save(user);
} catch (ValidationException v) {
final String msg = "Failed to disambiguate " + userName;
LOG.error(msg);
throw new IllegalArgumentException(msg);
}
}
// Call again to assign desired roles and service account flag
return ensureUserHelper(userName, password, firstName, lastName, email, expectedRoles, isServiceAccount);
}
}
@Nullable
public String ensureUserHelper(String userName, String password, String firstName, String lastName, String email,
Set expectedRoles, boolean isServiceAccount) {
User previousUser = null;
try {
previousUser = userService.load(userName);
if (previousUser == null
|| !previousUser.getRoleIds().containsAll(expectedRoles)
|| !Objects.equals(isServiceAccount, previousUser.isServiceAccount())) {
final String msg = "Invalid user '" + userName + "', fixing it.";
LOG.debug(msg);
throw new IllegalArgumentException(msg);
}
} catch (IllegalArgumentException ignored) {
LOG.info("{} user is missing or invalid, re-adding it as a built-in user.", userName);
final User fixedUser;
if (previousUser != null) {
fixedUser = previousUser;
fixedUser.setRoleIds(expectedRoles);
fixedUser.setServiceAccount(isServiceAccount);
} else {
fixedUser = userService.create();
fixedUser.setName(userName);
fixedUser.setFirstLastFullNames(firstName, lastName);
fixedUser.setPassword(password);
fixedUser.setEmail(email);
fixedUser.setPermissions(Collections.emptyList());
fixedUser.setRoleIds(expectedRoles);
fixedUser.setTimeZone(DateTimeZone.UTC);
fixedUser.setServiceAccount(isServiceAccount);
}
try {
// This performs an upsert to avoid any race condition in creating the user
return userService.save(fixedUser);
} catch (ValidationException e) {
LOG.error("Unable to save fixed '" + userName + "' user, please restart Graylog to fix this.", e);
}
}
if (previousUser == null) {
LOG.error("Unable to access fixed '" + userName + "' user, please restart Graylog to fix this.");
return null;
}
return previousUser.getId();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy