/*
* Copyright 2016 ThoughtWorks, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.thoughtworks.go.domain;
import com.thoughtworks.go.config.*;
import com.thoughtworks.go.config.materials.MaterialConfigs;
import com.thoughtworks.go.domain.config.Admin;
import com.thoughtworks.go.helper.GoConfigMother;
import com.thoughtworks.go.helper.StageConfigMother;
import org.apache.commons.collections.map.SingletonMap;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
public class ApprovalTest {
public static final String DEFAULT_GROUP = "defaultGroup";
@Before
public void setUp() throws Exception {
}
@Test
public void shouldNotAssignType() throws Exception {
Approval approval = new Approval();
approval.setConfigAttributes(new SingletonMap(Approval.TYPE, Approval.SUCCESS));
assertThat(approval.getType(), is(Approval.SUCCESS));
approval.setConfigAttributes(new HashMap());
assertThat(approval.getType(), is(Approval.SUCCESS));
approval.setConfigAttributes(new SingletonMap(Approval.TYPE, Approval.MANUAL));
assertThat(approval.getType(), is(Approval.MANUAL));
approval.setConfigAttributes(new HashMap());
assertThat(approval.getType(), is(Approval.MANUAL));
}
@Test
public void shouldValidateApprovalType() throws Exception {
Approval approval = new Approval();
approval.setConfigAttributes(new SingletonMap(Approval.TYPE, "not-manual-or-success"));
assertThat(approval.getType(), is("not-manual-or-success"));
approval.validate(ConfigSaveValidationContext.forChain(new BasicCruiseConfig(), new BasicPipelineConfigs()));
assertThat(approval.errors().firstError(), is("You have defined approval type as 'not-manual-or-success'. Approval can only be of the type 'manual' or 'success'."));
}
@Test
public void shouldFailValidateWhenUsersWithoutOperatePermissionOnGroupAreAuthorizedToApproveStage_WithPipelineConfigSaveValidationContext() {
CruiseConfig cruiseConfig = cruiseConfigWithSecurity(
new RoleConfig(new CaseInsensitiveString("role"), new RoleUser(new CaseInsensitiveString("first")), new RoleUser(new CaseInsensitiveString("second"))), new AdminUser(
new CaseInsensitiveString("admin")));
addUserAndRoleToDefaultGroup(cruiseConfig, "user", "role");
PipelineConfig pipeline = cruiseConfig.find(DEFAULT_GROUP, 0);
StageConfig stage = pipeline.get(0);
StageConfigMother.addApprovalWithUsers(stage, "not-present");
Approval approval = stage.getApproval();
approval.validate(PipelineConfigSaveValidationContext.forChain(true, DEFAULT_GROUP, cruiseConfig, pipeline, stage));
AdminUser user = approval.getAuthConfig().getUsers().get(0);
assertThat(user.errors().isEmpty(), is(false));
assertThat(user.errors().on("name"), is("User \"not-present\" who is not authorized to operate pipeline group can not be authorized to approve stage"));
}
@Test
public void shouldPassValidateWhenNoPermissionAreSetupOnGroupAndUserIsAuthorizedToApproveStage_WithPipelineConfigSaveValidationContext() {
CruiseConfig cruiseConfig = cruiseConfigWithSecurity(
new RoleConfig(new CaseInsensitiveString("role"),
new RoleUser(new CaseInsensitiveString("first")),
new RoleUser(new CaseInsensitiveString("second"))),
new AdminUser(
new CaseInsensitiveString("admin")));
PipelineConfig pipeline = cruiseConfig.find(DEFAULT_GROUP, 0);
StageConfig stage = pipeline.get(0);
StageConfigMother.addApprovalWithUsers(stage, "not-present");
Approval approval = stage.getApproval();
approval.validate(PipelineConfigSaveValidationContext.forChain(true, DEFAULT_GROUP, cruiseConfig, pipeline, stage));
assertNoErrors(approval.getAuthConfig().getUsers().get(0));
}
@Test
public void shouldPassValidateWhenARoleIsAdminOnGroupAndThatRoleIsAuthorizedToApproveStage_WithPipelineConfigSaveValidationContext() {
CruiseConfig cruiseConfig = cruiseConfigWithSecurity(
new RoleConfig(new CaseInsensitiveString("role"),
new RoleUser(new CaseInsensitiveString("first")),
new RoleUser(new CaseInsensitiveString("second"))),
new AdminUser(new CaseInsensitiveString("admin")));
addUserAsOperatorToDefaultGroup(cruiseConfig, "user");
addRoleAsAdminToDefaultGroup(cruiseConfig, "role");
PipelineConfig pipeline = cruiseConfig.find(DEFAULT_GROUP, 0);
StageConfig stage = pipeline.get(0);
StageConfigMother.addApprovalWithRoles(stage, "role");
Approval approval = stage.getApproval();
approval.validate(PipelineConfigSaveValidationContext.forChain(true, DEFAULT_GROUP, cruiseConfig, pipeline, stage));
assertNoErrors(approval.getAuthConfig().getRoles().get(0));
}
@Test
public void shouldReturnDisplayNameForApprovalType() {
Approval approval = Approval.automaticApproval();
assertThat(approval.getDisplayName(), is("On Success"));
approval = Approval.manualApproval();
assertThat(approval.getDisplayName(), is("Manual"));
}
@Test
public void shouldOverwriteExistingUsersWhileSettingNewUsers() {
Approval approval = Approval.automaticApproval();
approval.getAuthConfig().add(new AdminUser(new CaseInsensitiveString("sachin")));
approval.getAuthConfig().add(new AdminRole(new CaseInsensitiveString("admin")));
List names = new ArrayList();
names.add(nameMap("awesome_shilpa"));
names.add(nameMap("youth"));
names.add(nameMap(""));
List roles = new ArrayList();
roles.add(nameMap("role1"));
roles.add(nameMap("role2"));
roles.add(nameMap(""));
approval.setOperatePermissions(names, roles);
assertThat(approval.getAuthConfig().size(), is(4));
assertThat(approval.getAuthConfig(), hasItem((Admin) new AdminUser(new CaseInsensitiveString("awesome_shilpa"))));
assertThat(approval.getAuthConfig(), hasItem((Admin) new AdminUser(new CaseInsensitiveString("youth"))));
assertThat(approval.getAuthConfig(), hasItem((Admin) new AdminRole(new CaseInsensitiveString("role1"))));
assertThat(approval.getAuthConfig(), hasItem((Admin) new AdminRole(new CaseInsensitiveString("role2"))));
}
@Test
public void shouldClearAllPermissions() {
Approval approval = Approval.automaticApproval();
approval.getAuthConfig().add(new AdminUser(new CaseInsensitiveString("sachin")));
approval.getAuthConfig().add(new AdminRole(new CaseInsensitiveString("admin")));
approval.removeOperatePermissions();
assertThat(approval.getAuthConfig().isEmpty(), is(true));
}
@Test
public void shouldClearAllPermissionsWhenTheAttributesAreNull() {
Approval approval = Approval.automaticApproval();
approval.getAuthConfig().add(new AdminUser(new CaseInsensitiveString("sachin")));
approval.getAuthConfig().add(new AdminRole(new CaseInsensitiveString("admin")));
approval.setOperatePermissions(null, null);
assertThat(approval.getAuthConfig().isEmpty(), is(true));
}
@Test
public void validate_shouldNotAllow_UserInApprovalListButNotInOperationList() {
CruiseConfig cruiseConfig = cruiseConfigWithSecurity(
new RoleConfig(new CaseInsensitiveString("role"), new RoleUser(new CaseInsensitiveString("first")), new RoleUser(new CaseInsensitiveString("second"))), new AdminUser(
new CaseInsensitiveString("admin")));
PipelineConfigs group = addUserAndRoleToDefaultGroup(cruiseConfig, "user", "role");
PipelineConfig pipeline = cruiseConfig.find(DEFAULT_GROUP, 0);
StageConfig stage = pipeline.get(0);
StageConfigMother.addApprovalWithUsers(stage, "not-present");
Approval approval = stage.getApproval();
approval.validate(ConfigSaveValidationContext.forChain(cruiseConfig, group, pipeline, stage));
AdminUser user = approval.getAuthConfig().getUsers().get(0);
assertThat(user.errors().isEmpty(), is(false));
assertThat(user.errors().on("name"), is("User \"not-present\" who is not authorized to operate pipeline group can not be authorized to approve stage"));
}
@Test
public void validate_shouldNotAllowRoleInApprovalListButNotInOperationList() throws Exception {
CruiseConfig cruiseConfig = cruiseConfigWithSecurity(
new RoleConfig(new CaseInsensitiveString("role"), new RoleUser(new CaseInsensitiveString("first")), new RoleUser(new CaseInsensitiveString("second"))), new AdminUser(
new CaseInsensitiveString("admin")));
PipelineConfigs group = addUserAndRoleToDefaultGroup(cruiseConfig, "user", "role");
PipelineConfig pipeline = cruiseConfig.find(DEFAULT_GROUP, 0);
StageConfig stage = pipeline.get(0);
StageConfigMother.addApprovalWithRoles(stage, "not-present");
Approval approval = stage.getApproval();
approval.validate(ConfigSaveValidationContext.forChain(cruiseConfig, group, pipeline, stage));
AdminRole user = approval.getAuthConfig().getRoles().get(0);
assertThat(user.errors().isEmpty(), is(false));
assertThat(user.errors().on("name"), is("Role \"not-present\" who is not authorized to operate pipeline group can not be authorized to approve stage"));
}
@Test
public void validate_shouldAllowUserWhoseRoleHasOperatePermission() throws Exception {
CruiseConfig cruiseConfig = cruiseConfigWithSecurity(
new RoleConfig(new CaseInsensitiveString("role"), new RoleUser(new CaseInsensitiveString("first")), new RoleUser(new CaseInsensitiveString("second"))), new AdminUser(
new CaseInsensitiveString("admin")));
PipelineConfigs group = addUserAndRoleToDefaultGroup(cruiseConfig, "user", "role");
PipelineConfig pipeline = cruiseConfig.find(DEFAULT_GROUP, 0);
StageConfig stage = pipeline.get(0);
StageConfigMother.addApprovalWithUsers(stage, "first");
Approval approval = stage.getApproval();
approval.validate(ConfigSaveValidationContext.forChain(cruiseConfig, group, pipeline, stage));
assertNoErrors(approval.getAuthConfig().getUsers().get(0));
}
@Test
public void validate_shouldAllowUserWhoIsDefinedInGroup() throws Exception {
CruiseConfig cruiseConfig = cruiseConfigWithSecurity(
new RoleConfig(new CaseInsensitiveString("role"), new RoleUser(new CaseInsensitiveString("first")), new RoleUser(new CaseInsensitiveString("second"))), new AdminUser(
new CaseInsensitiveString("admin")));
PipelineConfigs group = addUserAndRoleToDefaultGroup(cruiseConfig, "user", "role");
PipelineConfig pipeline = cruiseConfig.find(DEFAULT_GROUP, 0);
StageConfig stage = pipeline.get(0);
StageConfigMother.addApprovalWithUsers(stage, "user");
Approval approval = stage.getApproval();
approval.validate(ConfigSaveValidationContext.forChain(cruiseConfig, group, pipeline, stage));
assertNoErrors(approval.getAuthConfig().getUsers().get(0));
}
@Test
public void validate_shouldAllowUserWhenSecurityIsNotDefinedInGroup() throws Exception {
CruiseConfig cruiseConfig = cruiseConfigWithSecurity(
new RoleConfig(new CaseInsensitiveString("role"), new RoleUser(new CaseInsensitiveString("first")), new RoleUser(new CaseInsensitiveString("second"))), new AdminUser(
new CaseInsensitiveString("admin")));
PipelineConfigs group = cruiseConfig.findGroup(DEFAULT_GROUP);
PipelineConfig pipeline = cruiseConfig.find(DEFAULT_GROUP, 0);
StageConfig stage = pipeline.get(0);
StageConfigMother.addApprovalWithUsers(stage, "user");
Approval approval = stage.getApproval();
approval.validate(ConfigSaveValidationContext.forChain(cruiseConfig, group, pipeline, stage));
assertNoErrors(approval.getAuthConfig().getUsers().get(0));
}
@Test
public void validate_shouldAllowAdminToOperateOnAStage() throws Exception {
CruiseConfig cruiseConfig = cruiseConfigWithSecurity(
new RoleConfig(new CaseInsensitiveString("role"), new RoleUser(new CaseInsensitiveString("first")), new RoleUser(new CaseInsensitiveString("second"))), new AdminUser(
new CaseInsensitiveString("admin")));
PipelineConfigs group = addUserAndRoleToDefaultGroup(cruiseConfig, "user", "role");
PipelineConfig pipeline = cruiseConfig.find(DEFAULT_GROUP, 0);
StageConfig stage = pipeline.get(0);
StageConfigMother.addApprovalWithUsers(stage, "admin");
Approval approval = stage.getApproval();
approval.validate(ConfigSaveValidationContext.forChain(cruiseConfig, group, pipeline, stage));
assertNoErrors(approval.getAuthConfig().getUsers().get(0));
}
@Test
public void shouldShowBugWhichAllowsAUserWithoutOperatePermissionToOperateAStage() throws Exception {
CruiseConfig cruiseConfig = cruiseConfigWithSecurity(
new RoleConfig(new CaseInsensitiveString("role"),
new RoleUser(new CaseInsensitiveString("first")),
new RoleUser(new CaseInsensitiveString("second"))),
new AdminUser(new CaseInsensitiveString("admin")));
addRoleAsAdminToDefaultGroup(cruiseConfig, "role");
PipelineConfig pipeline = cruiseConfig.find(DEFAULT_GROUP, 0);
StageConfig stage = pipeline.get(0);
StageConfigMother.addApprovalWithUsers(stage, "first", "some-other-user-who-is-not-operate-authorized");
Approval approval = stage.getApproval();
approval.validate(PipelineConfigSaveValidationContext.forChain(true, DEFAULT_GROUP, cruiseConfig, pipeline, stage));
assertNoErrors(approval.getAuthConfig().getUsers().get(0));
/* https://github.com/gocd/gocd/pull/1779#issuecomment-170161521 */
assertNoErrors(approval.getAuthConfig().getUsers().get(1));
}
@Test
public void validate_shouldNotTryAndValidateWhenWithinTemplate() throws Exception {
CruiseConfig cruiseConfig = cruiseConfigWithSecurity(
new RoleConfig(new CaseInsensitiveString("role"), new RoleUser(new CaseInsensitiveString("first")), new RoleUser(new CaseInsensitiveString("second"))), new AdminUser(
new CaseInsensitiveString("admin")));
PipelineConfigs group = addUserAndRoleToDefaultGroup(cruiseConfig, "user", "role");
PipelineConfig pipeline = cruiseConfig.find(DEFAULT_GROUP, 0);
StageConfig stage = pipeline.get(0);
StageConfigMother.addApprovalWithUsers(stage, "not-present");
Approval approval = stage.getApproval();
approval.validate(ConfigSaveValidationContext.forChain(cruiseConfig, new TemplatesConfig(), stage));
assertNoErrors(approval.getAuthConfig().getUsers().get(0));
}
@Test
public void shouldValidateTree(){
Approval approval = new Approval(new AuthConfig(new AdminRole(new CaseInsensitiveString("role"))));
BasicCruiseConfig cruiseConfig = GoConfigMother.defaultCruiseConfig();
cruiseConfig.server().security().adminsConfig().addRole(new AdminRole(new CaseInsensitiveString("super-admin")));
PipelineConfig pipelineConfig = new PipelineConfig(new CaseInsensitiveString("p1"), new MaterialConfigs());
cruiseConfig.addPipeline("g1", pipelineConfig);
assertThat(approval.validateTree(PipelineConfigSaveValidationContext.forChain(true, "g1", cruiseConfig, pipelineConfig)), is(false));
assertThat(approval.getAuthConfig().errors().isEmpty(), is(false));
}
private CruiseConfig cruiseConfigWithSecurity(Role roleDefinition, Admin admins) {
CruiseConfig cruiseConfig = GoConfigMother.configWithPipelines("pipeline");
SecurityConfig securityConfig = cruiseConfig.server().security();
securityConfig.modifyPasswordFile(new PasswordFileConfig("foo.bar"));
securityConfig.addRole(roleDefinition);
securityConfig.adminsConfig().add(admins);
return cruiseConfig;
}
private PipelineConfigs addUserAndRoleToDefaultGroup(CruiseConfig cruiseConfig, final String user, final String role) {
PipelineConfigs group = cruiseConfig.findGroup(DEFAULT_GROUP);
addUserAsOperatorToDefaultGroup(cruiseConfig, user);
addRoleAsOperatorToDefaultGroup(cruiseConfig, role);
return group;
}
private void addRoleAsOperatorToDefaultGroup(CruiseConfig goConfig, String role) {
PipelineConfigs group = goConfig.findGroup(DEFAULT_GROUP);
group.getAuthorization().getOperationConfig().add(new AdminRole(new CaseInsensitiveString(role)));
}
private PipelineConfigs addRoleAsAdminToDefaultGroup(CruiseConfig cruiseConfig, String role) {
PipelineConfigs group = cruiseConfig.findGroup(DEFAULT_GROUP);
group.getAuthorization().getAdminsConfig().add(new AdminRole(new CaseInsensitiveString(role)));
return group;
}
private PipelineConfigs addUserAsOperatorToDefaultGroup(CruiseConfig cruiseConfig, String user) {
PipelineConfigs group = cruiseConfig.findGroup(DEFAULT_GROUP);
group.getAuthorization().getOperationConfig().add(new AdminUser(new CaseInsensitiveString(user)));
return group;
}
private HashMap nameMap(final String name) {
HashMap nameMap = new HashMap();
nameMap.put("name", name);
return nameMap;
}
private void assertNoErrors(Admin userOrRole) {
assertThat(userOrRole.errors().getAll().toString(), userOrRole.errors().isEmpty(), is(true));
}
}