diff --git a/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/GroupRolesBean.java b/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/GroupRolesBean.java index d79da30410..2f68710424 100644 --- a/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/GroupRolesBean.java +++ b/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/GroupRolesBean.java @@ -16,6 +16,8 @@ package com.pinterest.deployservice.bean; import com.fasterxml.jackson.annotation.JsonProperty; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import org.apache.commons.lang.builder.ReflectionToStringBuilder; import javax.validation.constraints.NotEmpty; @@ -36,45 +38,47 @@ public class GroupRolesBean implements Updatable { @JsonProperty("name") private String group_name; + @NotEmpty @JsonProperty("resource") private String resource_id; + @NotNull @JsonProperty("type") - private Resource.Type resource_type; + private AuthZResource.Type resource_type; @NotNull @JsonProperty("role") - private Role role; + private TeletraanPrincipalRoles role; public String getGroup_name() { return group_name; } - public void setGroup_name(String user_name) { - this.group_name = user_name; + public void setGroup_name(String userName) { + this.group_name = userName; } public String getResource_id() { return resource_id; } - public void setResource_id(String resource_id) { - this.resource_id = resource_id; + public void setResource_id(String resourceId) { + this.resource_id = resourceId; } - public Resource.Type getResource_type() { + public AuthZResource.Type getResource_type() { return resource_type; } - public void setResource_type(Resource.Type resource_type) { - this.resource_type = resource_type; + public void setResource_type(AuthZResource.Type resourceType) { + this.resource_type = resourceType; } - public Role getRole() { + public TeletraanPrincipalRoles getRole() { return role; } - public void setRole(Role role) { + public void setRole(TeletraanPrincipalRoles role) { this.role = role; } diff --git a/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/Resource.java b/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/Resource.java deleted file mode 100644 index bf38cce26b..0000000000 --- a/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/Resource.java +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright 2016 Pinterest, 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.pinterest.deployservice.bean; - -public class Resource { - public enum Type { - ENV, GROUP, SYSTEM - } - - public final static String ALL = "*"; - public final static Resource SYSTEM_RESOURCE = new Resource(ALL, Type.SYSTEM); - - private String id; - private Type type; - - public Resource(String id, Type type) { - this.id = id; - this.type = type; - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public Type getType() { - return type; - } - - public void setType(Type type) { - this.type = type; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - Resource resource = (Resource) o; - - if (!id.equals(resource.id)) { - return false; - } - return type == resource.type; - - } - - @Override - public int hashCode() { - int result = id.hashCode(); - result = 31 * result + type.hashCode(); - return result; - } -} diff --git a/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/Role.java b/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/Role.java deleted file mode 100644 index 6ae70bf9ea..0000000000 --- a/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/Role.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright 2016 Pinterest, 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.pinterest.deployservice.bean; - -/** - * READER: - * Default role, everyone who is able to use Teletraan has READER access. - * PINGER: - * Role required to ping server. - * PUBLISHER: - * Role required to publish artifacts. - * OPERATOR: - * Role where user can modify a specific environment's config and - * perform deploy related actions. - * ADMIN: - * Role that has the same environment specific privileges as OPERATOR - * plus the ability specify new OPERATORS and ADMINs for said environment. - * When a new environment is created the creating user is the designated the - * first ADMIN. - */ -public enum Role { - READER(0), - PINGER(1), - PUBLISHER(1), - OPERATOR(10), - ADMIN(20); - - private int value; - - Role(int value) { - this.value = value; - } - - public boolean isAuthorized(Role requiredRole) { - return this == requiredRole || this.value > requiredRole.value; - } -} diff --git a/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/TeletraanPrincipalRoles.java b/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/TeletraanPrincipalRoles.java new file mode 100644 index 0000000000..b810dd5dd4 --- /dev/null +++ b/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/TeletraanPrincipalRoles.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2024, Pinterest Inc. All rights reserved. + */ +package com.pinterest.deployservice.bean; + +import com.pinterest.teletraan.universal.security.bean.RoleEnum; +import com.pinterest.teletraan.universal.security.bean.ValueBasedRole; + + +/** + * READER: + * Default role, everyone who is able to use Teletraan has READER access. + * PINGER: + * Role required to ping server. + * PUBLISHER: + * Role required to publish artifacts. + * OPERATOR: + * Role where user can modify a specific environment's config and + * perform deploy related actions. + * ADMIN: + * Role that has the same environment specific privileges as OPERATOR + * plus the ability specify new OPERATORS and ADMINs for said environment. + * When a new environment is created the creating user is the designated the + * first ADMIN. + */ +public enum TeletraanPrincipalRoles implements RoleEnum { + READ(-1), + READER(0), // legacy + PINGER(1), // legacy + PUBLISH(1), + PUBLISHER(1), // legacy + EXECUTE(9), + WRITE(9), + DELETE(9), + OPERATOR(10), // legacy + ADMIN(20); + + public class Names { + private Names() {} + public static final String ADMIN = "ADMIN"; + public static final String READER = "READER"; + public static final String OPERATOR = "OPERATOR"; + public static final String PINGER = "PINGER"; + + public static final String READ = "READ"; + public static final String WRITE = "WRITE"; + public static final String EXECUTE = "EXECUTE"; + public static final String DELETE = "DELETE"; + public static final String PUBLISH = "PUBLISH"; + } + + private ValueBasedRole role; + + TeletraanPrincipalRoles(int value) { + this.role = new ValueBasedRole(value); + } + + public ValueBasedRole getRole() { + return role; + } + + public boolean isEqualOrSuperior(TeletraanPrincipalRoles otherRole) { + return this.role.isEqualOrSuperior(otherRole.getRole()); + } +} diff --git a/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/TokenRolesBean.java b/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/TokenRolesBean.java index 8ddc65a8fc..a36da24dc0 100644 --- a/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/TokenRolesBean.java +++ b/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/TokenRolesBean.java @@ -16,8 +16,11 @@ package com.pinterest.deployservice.bean; import com.fasterxml.jackson.annotation.JsonProperty; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import org.apache.commons.lang.builder.ReflectionToStringBuilder; +import javax.annotation.Nonnull; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; @@ -38,19 +41,23 @@ public class TokenRolesBean implements Updatable { @JsonProperty("name") private String script_name; + @NotEmpty @JsonProperty("resource") private String resource_id; + @NotNull @JsonProperty("type") - private Resource.Type resource_type; + private AuthZResource.Type resource_type; + @NotEmpty @JsonProperty("token") private String token; @NotNull @JsonProperty("role") - private Role role; + private TeletraanPrincipalRoles role; + @NotNull @JsonProperty("expireDate") private Long expire_date; @@ -66,31 +73,31 @@ public String getScript_name() { return script_name; } - public void setScript_name(String script_name) { - this.script_name = script_name; + public void setScript_name(String scriptName) { + this.script_name = scriptName; } - public String getResource_id() { + public @Nonnull String getResource_id() { return resource_id; } - public void setResource_id(String resource_id) { - this.resource_id = resource_id; + public void setResource_id(String resourceId) { + this.resource_id = resourceId; } - public Resource.Type getResource_type() { + public AuthZResource.Type getResource_type() { return resource_type; } - public void setResource_type(Resource.Type resource_type) { - this.resource_type = resource_type; + public void setResource_type(AuthZResource.Type resourceType) { + this.resource_type = resourceType; } - public Role getRole() { + public TeletraanPrincipalRoles getRole() { return role; } - public void setRole(Role role) { + public void setRole(TeletraanPrincipalRoles role) { this.role = role; } @@ -98,8 +105,8 @@ public Long getExpire_date() { return expire_date; } - public void setExpire_date(Long expire_date) { - this.expire_date = expire_date; + public void setExpire_date(Long expireDate) { + this.expire_date = expireDate; } @Override diff --git a/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/UserRolesBean.java b/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/UserRolesBean.java index 2a7055584a..8eb5405579 100644 --- a/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/UserRolesBean.java +++ b/deploy-service/common/src/main/java/com/pinterest/deployservice/bean/UserRolesBean.java @@ -16,6 +16,8 @@ package com.pinterest.deployservice.bean; import com.fasterxml.jackson.annotation.JsonProperty; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import org.apache.commons.lang.builder.ReflectionToStringBuilder; import javax.validation.constraints.NotEmpty; @@ -36,49 +38,51 @@ public class UserRolesBean implements Updatable { @JsonProperty("name") private String user_name; + @NotEmpty @JsonProperty("resource") private String resource_id; + @NotNull @JsonProperty("type") - private Resource.Type resource_type; + private AuthZResource.Type resource_type; @NotNull @JsonProperty("role") - private Role role; + private TeletraanPrincipalRoles role; public String getUser_name() { return user_name; } - public void setUser_name(String user_name) { - this.user_name = user_name; + public void setUser_name(String userName) { + this.user_name = userName; } public String getResource_id() { return resource_id; } - public void setResource_id(String resource_id) { - this.resource_id = resource_id; + public void setResource_id(String resourceId) { + this.resource_id = resourceId; } - public Resource.Type getResource_type() { + public AuthZResource.Type getResource_type() { return resource_type; } - public void setResource_type(Resource.Type resource_type) { - this.resource_type = resource_type; + public void setResource_type(AuthZResource.Type resourceType) { + this.resource_type = resourceType; } - public Role getRole() { + public TeletraanPrincipalRoles getRole() { return role; } - public void setRole(Role role) { + public void setRole(TeletraanPrincipalRoles role) { this.role = role; } - public final static String UPDATE_CLAUSE = + public static final String UPDATE_CLAUSE = "user_name=VALUES(user_name)," + "resource_id=VALUES(resource_id)," + "resource_type=VALUES(resource_type)," + diff --git a/deploy-service/common/src/main/java/com/pinterest/deployservice/dao/GroupRolesDAO.java b/deploy-service/common/src/main/java/com/pinterest/deployservice/dao/GroupRolesDAO.java index 938e625b1a..a5be012bc1 100644 --- a/deploy-service/common/src/main/java/com/pinterest/deployservice/dao/GroupRolesDAO.java +++ b/deploy-service/common/src/main/java/com/pinterest/deployservice/dao/GroupRolesDAO.java @@ -4,9 +4,9 @@ * 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. @@ -16,22 +16,20 @@ package com.pinterest.deployservice.dao; import com.pinterest.deployservice.bean.GroupRolesBean; -import com.pinterest.deployservice.bean.Resource; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; import java.util.List; public interface GroupRolesDAO { void insert(GroupRolesBean bean) throws Exception; - void delete(String groupName, String resourceId, - Resource.Type resourceType) throws Exception; + void delete(String groupName, String resourceId, AuthZResource.Type resourceType) throws Exception; - void update(GroupRolesBean bean, String groupName, String resourceId, - Resource.Type resourceType) throws Exception; + void update(GroupRolesBean bean, String groupName, String resourceId, AuthZResource.Type resourceType) + throws Exception; - GroupRolesBean getByNameAndResource(String groupName, String resourceId, - Resource.Type resourceType) throws Exception; + GroupRolesBean getByNameAndResource(String groupName, String resourceId, AuthZResource.Type resourceType) + throws Exception; - List getByResource(String resourceId, - Resource.Type resourceType) throws Exception; + List getByResource(String resourceId, AuthZResource.Type resourceType) throws Exception; } diff --git a/deploy-service/common/src/main/java/com/pinterest/deployservice/dao/TokenRolesDAO.java b/deploy-service/common/src/main/java/com/pinterest/deployservice/dao/TokenRolesDAO.java index 15c1e19509..f69a55c172 100644 --- a/deploy-service/common/src/main/java/com/pinterest/deployservice/dao/TokenRolesDAO.java +++ b/deploy-service/common/src/main/java/com/pinterest/deployservice/dao/TokenRolesDAO.java @@ -4,9 +4,9 @@ * 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. @@ -15,25 +15,23 @@ */ package com.pinterest.deployservice.dao; -import com.pinterest.deployservice.bean.Resource; import com.pinterest.deployservice.bean.TokenRolesBean; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; import java.util.List; public interface TokenRolesDAO { void insert(TokenRolesBean bean) throws Exception; - void delete(String scriptName, String resourceId, - Resource.Type resourceType) throws Exception; + void delete(String scriptName, String resourceId, AuthZResource.Type resourceType) throws Exception; - void update(TokenRolesBean bean, String scriptName, String resourceId, - Resource.Type resourceType) throws Exception; + void update(TokenRolesBean bean, String scriptName, String resourceId, AuthZResource.Type resourceType) + throws Exception; TokenRolesBean getByToken(String token) throws Exception; - TokenRolesBean getByNameAndResource(String scriptName, String resourceId, - Resource.Type resourceType) throws Exception; + TokenRolesBean getByNameAndResource(String scriptName, String resourceId, AuthZResource.Type resourceType) + throws Exception; - List getByResource(String resourceId, - Resource.Type resourceType) throws Exception; + List getByResource(String resourceId, AuthZResource.Type resourceType) throws Exception; } diff --git a/deploy-service/common/src/main/java/com/pinterest/deployservice/dao/UserRolesDAO.java b/deploy-service/common/src/main/java/com/pinterest/deployservice/dao/UserRolesDAO.java index 4593c99a4d..b2a7e0616c 100644 --- a/deploy-service/common/src/main/java/com/pinterest/deployservice/dao/UserRolesDAO.java +++ b/deploy-service/common/src/main/java/com/pinterest/deployservice/dao/UserRolesDAO.java @@ -4,9 +4,9 @@ * 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. @@ -15,19 +15,21 @@ */ package com.pinterest.deployservice.dao; -import com.pinterest.deployservice.bean.Resource; import com.pinterest.deployservice.bean.UserRolesBean; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; import java.util.List; public interface UserRolesDAO { void insert(UserRolesBean bean) throws Exception; - void delete(String userName, String resourceId, Resource.Type resourceType) throws Exception; + void delete(String userName, String resourceId, AuthZResource.Type resourceType) throws Exception; - void update(UserRolesBean bean, String userName, String resourceId, Resource.Type resourceType) throws Exception; + void update(UserRolesBean bean, String userName, String resourceId, AuthZResource.Type resourceType) + throws Exception; - UserRolesBean getByNameAndResource(String userName, String resourceId, Resource.Type resourceType) throws Exception; + UserRolesBean getByNameAndResource(String userName, String resourceId, AuthZResource.Type resourceType) + throws Exception; - List getByResource(String resourceId, Resource.Type resourceType) throws Exception; + List getByResource(String resourceId, AuthZResource.Type resourceType) throws Exception; } diff --git a/deploy-service/common/src/main/java/com/pinterest/deployservice/db/DBGroupRolesDAOImpl.java b/deploy-service/common/src/main/java/com/pinterest/deployservice/db/DBGroupRolesDAOImpl.java index c0dde34c33..92b4d36710 100644 --- a/deploy-service/common/src/main/java/com/pinterest/deployservice/db/DBGroupRolesDAOImpl.java +++ b/deploy-service/common/src/main/java/com/pinterest/deployservice/db/DBGroupRolesDAOImpl.java @@ -4,9 +4,9 @@ * 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. @@ -16,9 +16,10 @@ package com.pinterest.deployservice.db; import com.pinterest.deployservice.bean.GroupRolesBean; -import com.pinterest.deployservice.bean.Resource; import com.pinterest.deployservice.bean.SetClause; import com.pinterest.deployservice.dao.GroupRolesDAO; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import org.apache.commons.dbcp.BasicDataSource; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.ResultSetHandler; @@ -66,14 +67,14 @@ public void insert(GroupRolesBean bean) throws Exception { @Override public void delete(String groupName, String resourceId, - Resource.Type resourceType) throws Exception { + AuthZResource.Type resourceType) throws Exception { new QueryRunner(dataSource).update(DELETE_TEMPLATE, groupName, resourceId, resourceType.toString()); } @Override public void update(GroupRolesBean bean, String groupName, String resourceId, - Resource.Type resourceType) throws Exception { + AuthZResource.Type resourceType) throws Exception { SetClause setClause = bean.genSetClause(); String clause = String.format(UPDATE_TEMPLATE, setClause.getClause()); setClause.addValue(groupName); @@ -84,7 +85,7 @@ public void update(GroupRolesBean bean, String groupName, String resourceId, @Override public GroupRolesBean getByNameAndResource(String groupName, String resourceId, - Resource.Type resourceType) throws Exception { + AuthZResource.Type resourceType) throws Exception { ResultSetHandler h = new BeanHandler<>(GroupRolesBean.class); return new QueryRunner(dataSource).query(GET_BY_NAME_AND_RESOURCE, h, groupName, resourceId, resourceType.toString()); @@ -92,7 +93,7 @@ public GroupRolesBean getByNameAndResource(String groupName, String resourceId, @Override public List getByResource(String resourceId, - Resource.Type resourceType) throws Exception { + AuthZResource.Type resourceType) throws Exception { ResultSetHandler> h = new BeanListHandler<>(GroupRolesBean.class); return new QueryRunner(dataSource).query(GET_BY_RESOURCE, h, resourceId, resourceType.toString()); diff --git a/deploy-service/common/src/main/java/com/pinterest/deployservice/db/DBTokenRolesDAOImpl.java b/deploy-service/common/src/main/java/com/pinterest/deployservice/db/DBTokenRolesDAOImpl.java index af6b45683f..cace700306 100644 --- a/deploy-service/common/src/main/java/com/pinterest/deployservice/db/DBTokenRolesDAOImpl.java +++ b/deploy-service/common/src/main/java/com/pinterest/deployservice/db/DBTokenRolesDAOImpl.java @@ -4,9 +4,9 @@ * 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. @@ -15,10 +15,11 @@ */ package com.pinterest.deployservice.db; -import com.pinterest.deployservice.bean.Resource; import com.pinterest.deployservice.bean.SetClause; import com.pinterest.deployservice.bean.TokenRolesBean; import com.pinterest.deployservice.dao.TokenRolesDAO; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import org.apache.commons.dbcp.BasicDataSource; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.ResultSetHandler; @@ -65,14 +66,14 @@ public void insert(TokenRolesBean bean) throws Exception { @Override public void delete(String userName, String resourceId, - Resource.Type resourceType) throws Exception { + AuthZResource.Type resourceType) throws Exception { new QueryRunner(dataSource).update(DELETE_TEMPLATE, userName, resourceId, resourceType.toString()); } @Override public void update(TokenRolesBean bean, String userName, String resourceId, - Resource.Type resourceType) throws Exception { + AuthZResource.Type resourceType) throws Exception { SetClause setClause = bean.genSetClause(); String clause = String.format(UPDATE_TEMPLATE, setClause.getClause()); setClause.addValue(userName); @@ -89,7 +90,7 @@ public TokenRolesBean getByToken(String token) throws Exception { @Override public TokenRolesBean getByNameAndResource(String userName, String resourceId, - Resource.Type resourceType) throws Exception { + AuthZResource.Type resourceType) throws Exception { ResultSetHandler h = new BeanHandler<>(TokenRolesBean.class); return new QueryRunner(dataSource).query(GET_BY_NAME_AND_RESOURCE, h, userName, resourceId, resourceType.toString()); @@ -97,7 +98,7 @@ public TokenRolesBean getByNameAndResource(String userName, String resourceId, @Override public List getByResource(String resourceId, - Resource.Type resourceType) throws Exception { + AuthZResource.Type resourceType) throws Exception { ResultSetHandler> h = new BeanListHandler<>(TokenRolesBean.class); return new QueryRunner(dataSource).query(GET_BY_RESOURCE, h, resourceId, resourceType.toString()); diff --git a/deploy-service/common/src/main/java/com/pinterest/deployservice/db/DBUserRolesDAOImpl.java b/deploy-service/common/src/main/java/com/pinterest/deployservice/db/DBUserRolesDAOImpl.java index 5b4bbed9a6..cfb485ad50 100644 --- a/deploy-service/common/src/main/java/com/pinterest/deployservice/db/DBUserRolesDAOImpl.java +++ b/deploy-service/common/src/main/java/com/pinterest/deployservice/db/DBUserRolesDAOImpl.java @@ -4,9 +4,9 @@ * 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. @@ -15,10 +15,11 @@ */ package com.pinterest.deployservice.db; -import com.pinterest.deployservice.bean.Resource; import com.pinterest.deployservice.bean.SetClause; import com.pinterest.deployservice.bean.UserRolesBean; import com.pinterest.deployservice.dao.UserRolesDAO; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import org.apache.commons.dbcp.BasicDataSource; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.ResultSetHandler; @@ -62,14 +63,14 @@ public void insert(UserRolesBean bean) throws Exception { @Override public void delete(String userName, String resourceId, - Resource.Type resourceType) throws Exception { + AuthZResource.Type resourceType) throws Exception { new QueryRunner(dataSource).update(DELETE_TEMPLATE, userName, resourceId, resourceType.toString()); } @Override public void update(UserRolesBean bean, String userName, String resourceId, - Resource.Type resourceType) throws Exception { + AuthZResource.Type resourceType) throws Exception { SetClause setClause = bean.genSetClause(); String clause = String.format(UPDATE_TEMPLATE, setClause.getClause()); setClause.addValue(userName); @@ -80,7 +81,7 @@ public void update(UserRolesBean bean, String userName, String resourceId, @Override public UserRolesBean getByNameAndResource(String userName, String resourceId, - Resource.Type resourceType) throws Exception { + AuthZResource.Type resourceType) throws Exception { ResultSetHandler h = new BeanHandler<>(UserRolesBean.class); return new QueryRunner(dataSource).query(GET_BY_NAME_AND_RESOURCE, h, userName, resourceId, resourceType.toString()); @@ -88,7 +89,7 @@ public UserRolesBean getByNameAndResource(String userName, String resourceId, @Override public List getByResource(String resourceId, - Resource.Type resourceType) throws Exception { + AuthZResource.Type resourceType) throws Exception { ResultSetHandler> h = new BeanListHandler<>(UserRolesBean.class); return new QueryRunner(dataSource).query(GET_BY_RESOURCE, h, resourceId, resourceType.toString()); diff --git a/deploy-service/common/src/test/java/com/pinterest/deployservice/db/DBDAOTest.java b/deploy-service/common/src/test/java/com/pinterest/deployservice/db/DBDAOTest.java index c8e6de8ebf..f69967a379 100644 --- a/deploy-service/common/src/test/java/com/pinterest/deployservice/db/DBDAOTest.java +++ b/deploy-service/common/src/test/java/com/pinterest/deployservice/db/DBDAOTest.java @@ -47,13 +47,12 @@ import com.pinterest.deployservice.bean.PromoteBean; import com.pinterest.deployservice.bean.PromoteType; import com.pinterest.deployservice.bean.RatingBean; -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; import com.pinterest.deployservice.bean.ScheduleBean; import com.pinterest.deployservice.bean.ScheduleState; import com.pinterest.deployservice.bean.TagBean; import com.pinterest.deployservice.bean.TagTargetType; import com.pinterest.deployservice.bean.TagValue; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; import com.pinterest.deployservice.bean.TokenRolesBean; import com.pinterest.deployservice.bean.UserRolesBean; import com.pinterest.deployservice.common.CommonUtils; @@ -75,8 +74,7 @@ import com.pinterest.deployservice.dao.TokenRolesDAO; import com.pinterest.deployservice.dao.UserRolesDAO; import com.pinterest.deployservice.dao.UtilDAO; - - +import com.pinterest.teletraan.universal.security.bean.AuthZResource; import com.ibatis.common.jdbc.ScriptRunner; import com.mysql.management.driverlaunched.ServerLauncherSocketFactory; import org.apache.commons.dbcp.BasicDataSource; @@ -923,13 +921,13 @@ public void testUserRolesDAO() throws Exception { UserRolesBean bean = new UserRolesBean(); bean.setUser_name("test"); bean.setResource_id("envTest"); - bean.setResource_type(Resource.Type.ENV); - bean.setRole(Role.ADMIN); + bean.setResource_type(AuthZResource.Type.ENV); + bean.setRole(TeletraanPrincipalRoles.ADMIN); userRolesDAO.insert(bean); UserRolesBean bean2 = - userRolesDAO.getByNameAndResource("test", "envTest", Resource.Type.ENV); - assertEquals(bean2.getRole(), Role.ADMIN); + userRolesDAO.getByNameAndResource("test", "envTest", AuthZResource.Type.ENV); + assertEquals(bean2.getRole(), TeletraanPrincipalRoles.ADMIN); } @Test @@ -937,13 +935,13 @@ public void testGroupRolesDAO() throws Exception { GroupRolesBean bean = new GroupRolesBean(); bean.setGroup_name("group"); bean.setResource_id("123"); - bean.setResource_type(Resource.Type.ENV); - bean.setRole(Role.ADMIN); + bean.setResource_type(AuthZResource.Type.ENV); + bean.setRole(TeletraanPrincipalRoles.ADMIN); groupRolesDAO.insert(bean); GroupRolesBean bean2 = - groupRolesDAO.getByNameAndResource("group", "123", Resource.Type.ENV); - assertEquals(bean2.getRole(), Role.ADMIN); + groupRolesDAO.getByNameAndResource("group", "123", AuthZResource.Type.ENV); + assertEquals(bean2.getRole(), TeletraanPrincipalRoles.ADMIN); } @Test @@ -952,14 +950,14 @@ public void testTokenRolesDAO() throws Exception { bean.setScript_name("test"); bean.setToken("token"); bean.setResource_id("envTest"); - bean.setResource_type(Resource.Type.ENV); - bean.setRole(Role.ADMIN); + bean.setResource_type(AuthZResource.Type.ENV); + bean.setRole(TeletraanPrincipalRoles.ADMIN); bean.setExpire_date(System.currentTimeMillis()); tokenRolesDAO.insert(bean); TokenRolesBean bean2 = - tokenRolesDAO.getByNameAndResource("test", "envTest", Resource.Type.ENV); - assertEquals(bean2.getRole(), Role.ADMIN); + tokenRolesDAO.getByNameAndResource("test", "envTest", AuthZResource.Type.ENV); + assertEquals(bean2.getRole(), TeletraanPrincipalRoles.ADMIN); } @@ -1061,7 +1059,7 @@ public void testScheduleDAO() throws Exception { assertEquals(updatedBean.getHost_numbers(), "50,60,500"); } - + @Test public void testUtilDAO() throws Exception { StringBuilder lockNameBuilder = new StringBuilder(); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/ConfigHelper.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/ConfigHelper.java index 59f35c0d03..14598a9e73 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/ConfigHelper.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/ConfigHelper.java @@ -133,7 +133,7 @@ public static TeletraanServiceContext setupContext(TeletraanServiceConfiguration context.setScheduleDAO(new DBScheduleDAOImpl(dataSource)); // Inject proper implementation based on config - context.setAuthorizer(configuration.getAuthorizationFactory().create(context)); + context.setAuthorizationFactory(configuration.getAuthorizationFactory()); context.setChatManager(configuration.getChatFactory().create()); context.setMailManager(configuration.getEmailFactory().createMailManager()); context.setHostGroupDAO(configuration.getHostGroupFactory().createHostGroupDAO()); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/TeletraanAgentService.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/TeletraanAgentService.java index fe37538f44..151f06213d 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/TeletraanAgentService.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/TeletraanAgentService.java @@ -15,9 +15,12 @@ */ package com.pinterest.teletraan; +import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature; + import com.pinterest.teletraan.health.GenericHealthCheck; import com.pinterest.teletraan.resource.Pings; import io.dropwizard.Application; +import io.dropwizard.auth.AuthDynamicFeature; import io.dropwizard.setup.Environment; import io.dropwizard.configuration.EnvironmentVariableSubstitutor; import io.dropwizard.configuration.SubstitutingSourceProvider; @@ -43,7 +46,10 @@ public void initialize(Bootstrap bootstrap) { public void run(TeletraanServiceConfiguration configuration, Environment environment) throws Exception { TeletraanServiceContext context = ConfigHelper.setupContext(configuration); environment.jersey().register(context); - environment.jersey().register(configuration.getAuthenticationFactory().create(context)); + environment + .jersey() + .register(new AuthDynamicFeature(configuration.getAuthenticationFactory().create(context))); + environment.jersey().register(RolesAllowedDynamicFeature.class); environment.jersey().register(Pings.class); environment.healthChecks().register("generic", new GenericHealthCheck(context)); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/TeletraanService.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/TeletraanService.java index d3007f425c..64dd067b9e 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/TeletraanService.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/TeletraanService.java @@ -18,8 +18,10 @@ import com.pinterest.teletraan.exception.GenericExceptionMapper; import com.pinterest.teletraan.health.GenericHealthCheck; import com.pinterest.teletraan.resource.*; +import com.pinterest.teletraan.universal.security.AuditLoggingFilter; import io.dropwizard.Application; +import io.dropwizard.auth.AuthDynamicFeature; import io.dropwizard.configuration.EnvironmentVariableSubstitutor; import io.dropwizard.configuration.SubstitutingSourceProvider; import io.dropwizard.jersey.jackson.JsonProcessingExceptionMapper; @@ -30,6 +32,7 @@ import io.swagger.jaxrs.listing.ApiListingResource; import io.swagger.jaxrs.listing.SwaggerSerializers; import org.eclipse.jetty.servlets.CrossOriginFilter; +import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature; import java.util.EnumSet; import javax.servlet.DispatcherType; @@ -55,8 +58,12 @@ public void initialize(Bootstrap bootstrap) { public void run(TeletraanServiceConfiguration configuration, Environment environment) throws Exception { TeletraanServiceContext context = ConfigHelper.setupContext(configuration); - environment.jersey().register(configuration.getAuthenticationFactory().create(context)); environment.jersey().register(context); + environment + .jersey() + .register(new AuthDynamicFeature(configuration.getAuthenticationFactory().create(context))); + environment.jersey().register(RolesAllowedDynamicFeature.class); + environment.jersey().register(AuditLoggingFilter.class); environment.jersey().register(Builds.class); environment.jersey().register(Commits.class); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/TeletraanServiceContext.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/TeletraanServiceContext.java index ad5c323bf0..9b2cd0909d 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/TeletraanServiceContext.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/TeletraanServiceContext.java @@ -17,14 +17,16 @@ import com.pinterest.deployservice.ServiceContext; import com.pinterest.deployservice.alerts.ExternalAlertFactory; -import com.pinterest.teletraan.security.Authorizer; +import com.pinterest.teletraan.config.AuthorizationFactory; +import com.pinterest.teletraan.universal.security.AuthZResourceExtractor; public class TeletraanServiceContext extends ServiceContext { - private Authorizer authorizer; private int maxDaysToKeep; private int maxBuildsToKeep; private ExternalAlertFactory externalAlertsFactory; + private AuthorizationFactory authorizationFactory; + private AuthZResourceExtractor.Factory authZResourceExtractorFactory; public ExternalAlertFactory getExternalAlertsFactory() { return externalAlertsFactory; @@ -35,14 +37,6 @@ public void setExternalAlertsFactory( this.externalAlertsFactory = externalAlertsFactory; } - public Authorizer getAuthorizer() { - return authorizer; - } - - public void setAuthorizer(Authorizer authz) { - this.authorizer = authz; - } - public int getMaxDaysToKeep() { return maxDaysToKeep; } @@ -59,4 +53,20 @@ public void setMaxBuildsToKeep(int maxBuildsToKeep) { this.maxBuildsToKeep = maxBuildsToKeep; } + public void setAuthorizationFactory(AuthorizationFactory authorizationFactory) { + this.authorizationFactory = authorizationFactory; + } + + public AuthorizationFactory getAuthorizationFactory() { + return authorizationFactory; + } + + public AuthZResourceExtractor.Factory getAuthZResourceExtractorFactory() { + return authZResourceExtractorFactory; + } + + public void setAuthZResourceExtractorFactory( + AuthZResourceExtractor.Factory authZResourceExtractorFactory) { + this.authZResourceExtractorFactory = authZResourceExtractorFactory; + } } diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/AnonymousAuthenticationFactory.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/AnonymousAuthenticationFactory.java index 2005b71ab5..cc4424fc54 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/AnonymousAuthenticationFactory.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/AnonymousAuthenticationFactory.java @@ -1,12 +1,12 @@ /** - * Copyright 2016 Pinterest, Inc. + * Copyright (c) 2016-2024 Pinterest, 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. @@ -17,8 +17,7 @@ import com.fasterxml.jackson.annotation.JsonTypeName; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.AnonymousAuthFilter; - +import com.pinterest.teletraan.universal.security.AnonymousAuthFilter; import javax.ws.rs.container.ContainerRequestFilter; @JsonTypeName("anonymous") diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/AuthorizationFactory.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/AuthorizationFactory.java index 7c1ebd7f3f..96da79f100 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/AuthorizationFactory.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/AuthorizationFactory.java @@ -1,12 +1,12 @@ /** - * Copyright 2016 Pinterest, Inc. + * Copyright (c) 2016-2024 Pinterest, 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. @@ -17,10 +17,17 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.Authorizer; +import com.pinterest.teletraan.universal.security.bean.TeletraanPrincipal; +import io.dropwizard.auth.Authorizer; import io.dropwizard.jackson.Discoverable; @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") public interface AuthorizationFactory extends Discoverable { - Authorizer create(TeletraanServiceContext context) throws Exception; +

Authorizer

create(TeletraanServiceContext context) + throws Exception; + + default

Authorizer create( + TeletraanServiceContext context, Class

principalClass) throws Exception { + return create(context); + } } diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/OpenAuthorizationFactory.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/OpenAuthorizationFactory.java index 85b6ea0bba..adf179f6c6 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/OpenAuthorizationFactory.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/OpenAuthorizationFactory.java @@ -1,12 +1,12 @@ /** - * Copyright 2016 Pinterest, Inc. + * Copyright (c) 2016-2024 Pinterest, 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. @@ -15,26 +15,16 @@ */ package com.pinterest.teletraan.config; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonTypeName; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.OpenAuthorizer; +import com.pinterest.teletraan.universal.security.bean.TeletraanPrincipal; +import io.dropwizard.auth.Authorizer; +import io.dropwizard.auth.PermitAllAuthorizer; @JsonTypeName("open") public class OpenAuthorizationFactory implements AuthorizationFactory { - @JsonProperty - private String roleCacheSpec; - - public String getRoleCacheSpec() { - return roleCacheSpec; - } - - public void setRoleCacheSpec(String roleCacheSpec) { - this.roleCacheSpec = roleCacheSpec; - } - @Override - public OpenAuthorizer create(TeletraanServiceContext context) throws Exception { - return new OpenAuthorizer(); + public Authorizer create(TeletraanServiceContext context) throws Exception { + return new PermitAllAuthorizer<>(); } } diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/RoleAuthorizationFactory.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/RoleAuthorizationFactory.java new file mode 100644 index 0000000000..c17baf3376 --- /dev/null +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/RoleAuthorizationFactory.java @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2024 Pinterest, 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.pinterest.teletraan.config; + +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.pinterest.teletraan.TeletraanServiceContext; +import com.pinterest.teletraan.security.ScriptTokenRoleAuthorizer; +import com.pinterest.teletraan.security.UserRoleAuthorizer; +import com.pinterest.teletraan.universal.security.bean.ServicePrincipal; +import com.pinterest.teletraan.universal.security.bean.TeletraanPrincipal; +import com.pinterest.teletraan.universal.security.bean.UserPrincipal; +import io.dropwizard.auth.Authorizer; + +@JsonTypeName("role") +public class RoleAuthorizationFactory implements AuthorizationFactory { + @Override + public

Authorizer

create(TeletraanServiceContext context) + throws Exception { + throw new UnsupportedOperationException( + "RoleAuthorizationFactory does not support this method. Use create(TeletraanServiceContext, Class

) instead."); + } + + @Override + public

Authorizer create( + TeletraanServiceContext context, Class

principalClass) throws Exception { + if (principalClass.equals(ServicePrincipal.class)) { + return new ScriptTokenRoleAuthorizer(context.getAuthZResourceExtractorFactory()); + } else if (principalClass.equals(UserPrincipal.class)) { + return new UserRoleAuthorizer(context, context.getAuthZResourceExtractorFactory()); + } + throw new UnsupportedOperationException("Unsupported principal class: " + principalClass); + } +} diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/TokenAuthenticationFactory.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/TokenAuthenticationFactory.java index b2296c1635..11e2503a41 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/TokenAuthenticationFactory.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/TokenAuthenticationFactory.java @@ -1,5 +1,5 @@ /** - * Copyright 2016 Pinterest, Inc. + * Copyright (c) 2016-2024 Pinterest, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,33 +15,43 @@ */ package com.pinterest.teletraan.config; +import java.util.Arrays; +import java.util.List; +import javax.validation.constraints.NotEmpty; +import javax.ws.rs.container.ContainerRequestFilter; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.SharedMetricRegistries; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonTypeName; +import com.github.benmanes.caffeine.cache.Caffeine; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.TokenAuthFilter; - -import javax.validation.constraints.NotEmpty; -import javax.ws.rs.container.ContainerRequestFilter; +import com.pinterest.teletraan.security.TeletraanScriptTokenProvider; +import com.pinterest.teletraan.universal.security.OAuthAuthenticator; +import com.pinterest.teletraan.universal.security.ScriptTokenAuthenticator; +import com.pinterest.teletraan.universal.security.bean.ScriptTokenPrincipal; +import com.pinterest.teletraan.universal.security.bean.ServicePrincipal; +import com.pinterest.teletraan.universal.security.bean.UserPrincipal; +import com.pinterest.teletraan.universal.security.bean.ValueBasedRole; + +import io.dropwizard.auth.AuthFilter; +import io.dropwizard.auth.Authorizer; +import io.dropwizard.auth.CachingAuthenticator; +import io.dropwizard.auth.chained.ChainedAuthFilter; +import io.dropwizard.auth.oauth.OAuthCredentialAuthFilter; @JsonTypeName("token") public class TokenAuthenticationFactory implements AuthenticationFactory { - @JsonProperty - @NotEmpty - private String userDataUrl; + @JsonProperty @NotEmpty private String userDataUrl; - @JsonProperty - private String groupDataUrl; + @JsonProperty private String groupDataUrl; - @JsonProperty - private String userNameKey; + @JsonProperty private String userNameKey; - @JsonProperty - private Boolean extractUserNameFromEmail; + @JsonProperty private Boolean extractUserNameFromEmail; - @JsonProperty - private String tokenCacheSpec; + @JsonProperty private String tokenCacheSpec; public String getUserDataUrl() { return userDataUrl; @@ -83,8 +93,68 @@ public void setGroupDataUrl(String groupDataUrl) { this.groupDataUrl = groupDataUrl; } + @SuppressWarnings({"rawtypes", "unchecked"}) @Override public ContainerRequestFilter create(TeletraanServiceContext context) throws Exception { - return new TokenAuthFilter(userDataUrl, groupDataUrl, userNameKey, extractUserNameFromEmail, tokenCacheSpec, context); + List filters = createAuthFilters(context); + + return new ChainedAuthFilter(filters); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + List createAuthFilters(TeletraanServiceContext context) throws Exception { + MetricRegistry registry = SharedMetricRegistries.getDefault(); + Caffeine cacheBuilder = Caffeine.from(getTokenCacheSpec()); + + CachingAuthenticator> + cachingScriptTokenAuthenticator = + new CachingAuthenticator<>( + registry, + new ScriptTokenAuthenticator<>( + new TeletraanScriptTokenProvider(context)), + cacheBuilder); + AuthFilter> scriptTokenAuthFilter = + new OAuthCredentialAuthFilter.Builder>() + .setAuthenticator(cachingScriptTokenAuthenticator) + .setAuthorizer( + (Authorizer>) + context.getAuthorizationFactory() + .create(context, ServicePrincipal.class)) + .setPrefix("token") + .buildAuthFilter(); + + CachingAuthenticator cachingOAuthJwtAuthenticator = + new CachingAuthenticator<>( + registry, + new OAuthAuthenticator(getUserDataUrl(), getGroupDataUrl()), + cacheBuilder); + AuthFilter jwtTokenAuthFilter = + new OAuthCredentialAuthFilter.Builder() + .setAuthenticator(cachingOAuthJwtAuthenticator) + .setAuthorizer( + (Authorizer) + context.getAuthorizationFactory() + .create(context, UserPrincipal.class)) + .setPrefix("Bearer") + .buildAuthFilter(); + + // TODO: remove this after all the clients are updated to use the new token + // scheme + CachingAuthenticator cachingOAuthAuthenticator = + new CachingAuthenticator<>( + registry, + new OAuthAuthenticator(getUserDataUrl(), getGroupDataUrl()), + cacheBuilder); + AuthFilter oauthTokenAuthFilter = + new OAuthCredentialAuthFilter.Builder() + .setAuthenticator(cachingOAuthAuthenticator) + .setAuthorizer( + (Authorizer) + context.getAuthorizationFactory() + .create(context, UserPrincipal.class)) + .setPrefix("token") + .buildAuthFilter(); + + return Arrays.asList(scriptTokenAuthFilter, oauthTokenAuthFilter, jwtTokenAuthFilter); } } diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/TokenAuthorizationFactory.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/TokenAuthorizationFactory.java deleted file mode 100644 index edd48e4251..0000000000 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/config/TokenAuthorizationFactory.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright 2016 Pinterest, 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.pinterest.teletraan.config; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonTypeName; -import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.RoleAuthorizer; - -@JsonTypeName("role") -public class TokenAuthorizationFactory implements AuthorizationFactory { - @JsonProperty - private String roleCacheSpec; - - public String getRoleCacheSpec() { - return roleCacheSpec; - } - - public void setRoleCacheSpec(String roleCacheSpec) { - this.roleCacheSpec = roleCacheSpec; - } - - @Override - public RoleAuthorizer create(TeletraanServiceContext context) throws Exception { - return new RoleAuthorizer(context, roleCacheSpec); - } -} diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Builds.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Builds.java index 854512b745..dd648e2e08 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Builds.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Builds.java @@ -28,12 +28,15 @@ import com.pinterest.teletraan.TeletraanServiceContext; import com.pinterest.deployservice.events.BuildEventPublisher; import com.pinterest.deployservice.exception.TeletaanInternalException; -import com.pinterest.teletraan.security.Authorizer; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import io.swagger.annotations.*; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.security.RolesAllowed; import javax.validation.Valid; import javax.ws.rs.*; import javax.ws.rs.core.*; @@ -57,14 +60,12 @@ public class Builds { private final TagDAO tagDAO; private final Allowlist buildAllowlist; private final SourceControlManagerProxy sourceControlManagerProxy; - private final Authorizer authorizer; private final BuildEventPublisher buildEventPublisher; public Builds(@Context TeletraanServiceContext context) { buildDAO = context.getBuildDAO(); tagDAO = context.getTagDAO(); sourceControlManagerProxy = context.getSourceControlManagerProxy(); - authorizer = context.getAuthorizer(); buildAllowlist = context.getBuildAllowlist(); buildEventPublisher = context.getBuildEventPublisher(); deployDAO = context.getDeployDAO(); @@ -177,6 +178,7 @@ public List getBuildsWithTags(@QueryParam("commit") String scmComm value = "Publish a build", notes = "Publish a build given a build object", response = Response.class) + @RolesAllowed(TeletraanPrincipalRoles.Names.PUBLISH) public Response publish( @Context SecurityContext sc, @Context UriInfo uriInfo, @@ -245,10 +247,11 @@ public Response publish( @ApiOperation( value = "Delete a build", notes = "Deletes a build given a build id") + @RolesAllowed(TeletraanPrincipalRoles.Names.DELETE) + @ResourceAuthZInfo(type = AuthZResource.Type.BUILD) public void delete( @Context SecurityContext sc, @ApiParam(value = "BUILD id", required = true)@PathParam("id") String id) throws Exception { - authorizer.authorize(sc, new Resource(Resource.ALL, Resource.Type.SYSTEM), Role.OPERATOR); BuildBean buildBean = buildDAO.getById(id); if (buildBean == null) { throw new TeletaanInternalException(Response.Status.NOT_FOUND, String.format("BUILD %s does not exist.", id)); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/DeployCandidates.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/DeployCandidates.java index eb6a97debb..da9b33dfa2 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/DeployCandidates.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/DeployCandidates.java @@ -4,12 +4,10 @@ import com.pinterest.deployservice.bean.PingRequestBean; import com.pinterest.deployservice.bean.PingResponseBean; import com.pinterest.deployservice.bean.PingResult; -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; import com.pinterest.deployservice.handler.GoalAnalyst; import com.pinterest.deployservice.handler.PingHandler; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.Authorizer; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -17,6 +15,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.security.RolesAllowed; import javax.validation.Valid; import javax.ws.rs.Consumes; import javax.ws.rs.POST; @@ -34,11 +33,9 @@ public class DeployCandidates { private static final Logger LOG = LoggerFactory.getLogger(DeployCandidates.class); private PingHandler pingHandler; - private final Authorizer authorizer; public DeployCandidates(@Context TeletraanServiceContext context) { pingHandler = new PingHandler(context); - authorizer = context.getAuthorizer(); } @POST @@ -47,11 +44,11 @@ public DeployCandidates(@Context TeletraanServiceContext context) { value = "Get a set of deploy candidates to deploy", notes = "Returns a list of build bean", response = DeployCandidatesResponse.class) + @RolesAllowed(TeletraanPrincipalRoles.Names.PINGER) public DeployCandidatesResponse getDeployCandidates(@Context SecurityContext sc, @Context HttpHeaders headers, @ApiParam(value = "Ping request object", required = true)@Valid PingRequestBean requestBean) throws Exception { LOG.info("Receive ping request " + requestBean); - authorizer.authorize(sc, new Resource(Resource.ALL, Resource.Type.SYSTEM), Role.PINGER); boolean rate_limited = Boolean.parseBoolean(headers.getRequestHeaders().getFirst("x-envoy-low-watermark")); PingResult result = pingHandler.ping(requestBean, rate_limited); DeployCandidatesResponse resp = new DeployCandidatesResponse(); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/DeployConstraints.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/DeployConstraints.java index e2ad2bc50a..d13443ac7c 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/DeployConstraints.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/DeployConstraints.java @@ -6,13 +6,15 @@ import com.pinterest.deployservice.dao.EnvironDAO; import com.pinterest.deployservice.db.DatabaseUtil; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.Authorizer; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; import com.pinterest.teletraan.worker.DeployTagWorker; import io.swagger.annotations.*; import org.apache.commons.dbcp.BasicDataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.security.RolesAllowed; import javax.validation.Valid; import javax.ws.rs.*; import javax.ws.rs.core.Context; @@ -36,7 +38,6 @@ public class DeployConstraints { private DeployConstraintDAO deployConstraintDAO; private EnvironDAO environDAO; - private Authorizer authorizer; private BasicDataSource dataSource; private TeletraanServiceContext serviceContext; @@ -44,7 +45,6 @@ public DeployConstraints(@Context TeletraanServiceContext context) { serviceContext = context; deployConstraintDAO = context.getDeployConstraintDAO(); environDAO = context.getEnvironDAO(); - authorizer = context.getAuthorizer(); dataSource = context.getDataSource(); } @@ -57,7 +57,6 @@ public DeployConstraintBean get(@PathParam("envName") String envName, @PathParam("stageName") String stageName, @Context SecurityContext sc) throws Exception { EnvironBean envBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(envBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String deployConstraintId = envBean.getDeploy_constraint_id(); if (deployConstraintId == null) { LOG.warn("Environment {} does not have deploy constraint set up.", envBean); @@ -67,13 +66,14 @@ public DeployConstraintBean get(@PathParam("envName") String envName, } @POST + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = ResourceAuthZInfo.Location.PATH) public void update(@PathParam("envName") String envName, @PathParam("stageName") String stageName, @ApiParam(value = "Deploy Constraint Object to update in database", required = true) @Valid DeployConstraintBean deployConstraintBean, @Context SecurityContext sc) throws Exception { EnvironBean envBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(envBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String operator = sc.getUserPrincipal().getName(); String constraintId = envBean.getDeploy_constraint_id(); @@ -122,11 +122,12 @@ public void update(@PathParam("envName") String envName, @DELETE + @RolesAllowed(TeletraanPrincipalRoles.Names.DELETE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = ResourceAuthZInfo.Location.PATH) public void delete(@PathParam("envName") String envName, @PathParam("stageName") String stageName, @Context SecurityContext sc) throws Exception { EnvironBean envBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(envBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String operator = sc.getUserPrincipal().getName(); String constraintId = envBean.getDeploy_constraint_id(); if (constraintId == null) { diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Deploys.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Deploys.java index a907e45393..49ae448b72 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Deploys.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Deploys.java @@ -26,22 +26,22 @@ import com.pinterest.deployservice.bean.DeployQueryResultBean; import com.pinterest.deployservice.bean.DeployState; import com.pinterest.deployservice.bean.DeployType; -import com.pinterest.deployservice.bean.EnvironBean; -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; import com.pinterest.deployservice.dao.DeployDAO; -import com.pinterest.deployservice.dao.EnvironDAO; import com.pinterest.deployservice.db.DeployQueryFilter; import com.pinterest.deployservice.handler.DeployHandler; import com.pinterest.teletraan.TeletraanServiceContext; import com.pinterest.deployservice.exception.TeletaanInternalException; -import com.pinterest.teletraan.security.Authorizer; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo.Location; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; +import javax.annotation.security.RolesAllowed; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; @@ -72,17 +72,13 @@ @Consumes(MediaType.APPLICATION_JSON) public class Deploys { private static final Logger LOG = LoggerFactory.getLogger(Deploys.class); - private final static int DEFAULT_SIZE = 30; - private EnvironDAO environDAO; + private static final int DEFAULT_SIZE = 30; private DeployDAO deployDAO; private DeployHandler deployHandler; - private final Authorizer authorizer; public Deploys(@Context TeletraanServiceContext context) { - environDAO = context.getEnvironDAO(); deployDAO = context.getDeployDAO(); deployHandler = new DeployHandler(context); - authorizer = context.getAuthorizer(); } @GET @@ -147,14 +143,13 @@ public DeployQueryResultBean search( value = "Update deploy", notes = "Update deploy given a deploy id and a deploy object. Current only " + "acceptanceStatus and description are allowed to change.") + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = Location.BODY, beanClass = DeployBean.class) public void update( @Context SecurityContext sc, @ApiParam(value = "Deploy id", required = true)@PathParam("id") String id, @ApiParam(value = "Partially populated deploy object", required = true) DeployBean deployBean) throws Exception { - DeployBean originBean = Utils.getDeploy(deployDAO, id); - EnvironBean environBean = Utils.getEnvStage(environDAO, originBean.getEnv_id()); - authorizer.authorize(sc, new Resource(environBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String userName = sc.getUserPrincipal().getName(); deployHandler.update(id, deployBean); LOG.info("{} successfully updated deploy {} with {}", @@ -168,12 +163,11 @@ public void update( @ApiOperation( value = "Delete deploy info", notes = "Delete deploy info given a deploy id") + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = Location.BODY, beanClass = DeployBean.class) public void delete( @Context SecurityContext sc, @ApiParam(value = "Deploy id", required = true)@PathParam("id") String id) throws Exception { - DeployBean deployBean = Utils.getDeploy(deployDAO, id); - EnvironBean environBean = Utils.getEnvStage(environDAO, deployBean.getEnv_id()); - authorizer.authorize(sc, new Resource(environBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String userName = sc.getUserPrincipal().getName(); deployDAO.delete(id); LOG.info("Successfully deleted deploy {} by {}", id, userName); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvAgentConfigs.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvAgentConfigs.java index 8737117096..be67b5602d 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvAgentConfigs.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvAgentConfigs.java @@ -4,9 +4,9 @@ * 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. @@ -16,20 +16,22 @@ package com.pinterest.teletraan.resource; import com.pinterest.deployservice.bean.EnvironBean; -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; import com.pinterest.deployservice.common.Constants; import com.pinterest.deployservice.dao.EnvironDAO; import com.pinterest.deployservice.handler.ConfigHistoryHandler; import com.pinterest.deployservice.handler.EnvironHandler; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.Authorizer; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.security.RolesAllowed; import javax.validation.Valid; import javax.ws.rs.*; import javax.ws.rs.core.Context; @@ -46,13 +48,11 @@ public class EnvAgentConfigs { private EnvironDAO environDAO; private EnvironHandler environHandler; private ConfigHistoryHandler configHistoryHandler; - private Authorizer authorizer; public EnvAgentConfigs(@Context TeletraanServiceContext context) { environDAO = context.getEnvironDAO(); environHandler = new EnvironHandler(context); configHistoryHandler = new ConfigHistoryHandler(context); - authorizer = context.getAuthorizer(); } @GET @@ -72,13 +72,14 @@ public Map get( value = "Update agent configs", notes = "Updates environment agent configs given an environment name and stage name with a map of " + "name,value agent configs") + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = ResourceAuthZInfo.Location.PATH) public void update( @ApiParam(value = "Environment name", required = true)@PathParam("envName") String envName, @ApiParam(value = "Stage name", required = true)@PathParam("stageName") String stageName, @ApiParam(value = "Map of configs to update with", required = true)@Valid Map configs, @Context SecurityContext sc) throws Exception { EnvironBean envBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(envBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String userName = sc.getUserPrincipal().getName(); Utils.trimMapValues(configs); environHandler.updateAdvancedConfigs(envBean, configs, userName); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvAgents.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvAgents.java index c7ba89a9e1..9709cbb4e6 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvAgents.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvAgents.java @@ -4,9 +4,9 @@ * 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. @@ -21,9 +21,12 @@ import com.pinterest.deployservice.dao.EnvironDAO; import com.pinterest.teletraan.TeletraanServiceContext; import com.pinterest.deployservice.exception.TeletaanInternalException; -import com.pinterest.teletraan.security.Authorizer; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import io.swagger.annotations.*; +import javax.annotation.security.RolesAllowed; import javax.validation.constraints.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,7 +47,6 @@ public class EnvAgents { private EnvironDAO environDAO; private AgentDAO agentDAO; private AgentErrorDAO agentErrorDAO; - private Authorizer authorizer; public enum CountActionType { SERVING, @@ -55,7 +57,6 @@ public enum CountActionType { public EnvAgents(@Context TeletraanServiceContext context) { environDAO = context.getEnvironDAO(); - authorizer = context.getAuthorizer(); agentDAO = context.getAgentDAO(); agentErrorDAO = context.getAgentErrorDAO(); } @@ -96,6 +97,8 @@ public AgentErrorBean getAgentError( value = "Update host agent", notes = "Updates host agent specified by given environment name, stage name, and host id with given " + "agent object") + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = ResourceAuthZInfo.Location.PATH) public void update( @Context SecurityContext sc, @ApiParam(value = "Environment name", required = true)@PathParam("envName") String envName, @@ -103,7 +106,6 @@ public void update( @ApiParam(value = "Host id", required = true)@PathParam("hostId") String hostId, @ApiParam(value = "Agent object to update with", required = true)AgentBean agentBean) throws Exception { EnvironBean envBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(envBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String operator = sc.getUserPrincipal().getName(); agentDAO.update(hostId, envBean.getEnv_id(), agentBean); LOG.info("Successfully updated agent {} with {} in env {}/{} by {}.", @@ -115,13 +117,14 @@ public void update( @ApiOperation( value = "Reset failed deploys", notes = "Resets failing deploys given an environment name, stage name, and deploy id") + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = ResourceAuthZInfo.Location.PATH) public void resetFailedDeploys( @Context SecurityContext sc, @ApiParam(value = "Environment name", required = true)@PathParam("envName") String envName, @ApiParam(value = "Stage name", required = true)@PathParam("stageName") String stageName, @ApiParam(value = "Deploy id", required = true)@PathParam("deployId") String deployId) throws Exception { EnvironBean environBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(environBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String operator = sc.getUserPrincipal().getName(); agentDAO.resetFailedAgents(environBean.getEnv_id(), deployId); LOG.info("Successfully reset failed agents for deploy {} in env {}/{} by {}.", diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvAlarms.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvAlarms.java index 62727a854a..3989093318 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvAlarms.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvAlarms.java @@ -4,9 +4,9 @@ * 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. @@ -17,19 +17,21 @@ import com.pinterest.deployservice.bean.AlarmBean; import com.pinterest.deployservice.bean.EnvironBean; -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; import com.pinterest.deployservice.common.Constants; import com.pinterest.deployservice.dao.EnvironDAO; import com.pinterest.deployservice.handler.ConfigHistoryHandler; import com.pinterest.deployservice.handler.EnvironHandler; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.Authorizer; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; + +import javax.annotation.security.RolesAllowed; import javax.validation.Valid; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -49,13 +51,11 @@ public class EnvAlarms { private EnvironHandler environHandler; private EnvironDAO environDAO; private ConfigHistoryHandler configHistoryHandler; - private Authorizer authorizer; public EnvAlarms(@Context TeletraanServiceContext context) { environHandler = new EnvironHandler(context); configHistoryHandler = new ConfigHistoryHandler(context); environDAO = context.getEnvironDAO(); - authorizer = context.getAuthorizer(); } @GET @@ -66,10 +66,11 @@ public List get(@PathParam("envName") String envName, } @PUT + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = ResourceAuthZInfo.Location.PATH) public void update(@PathParam("envName") String envName, @PathParam("stageName") String stageName, - @Valid List alarmBeans, @Context SecurityContext sc) throws Exception { + @Valid List alarmBeans, @Context SecurityContext sc) throws Exception { EnvironBean environBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(environBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String userName = sc.getUserPrincipal().getName(); environHandler.updateAlarms(environBean, alarmBeans, userName); configHistoryHandler.updateConfigHistory(environBean.getEnv_id(), Constants.TYPE_ENV_ALARM, alarmBeans, userName); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvAlerts.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvAlerts.java index 9d25b2ba16..4f0a6458a9 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvAlerts.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvAlerts.java @@ -27,14 +27,14 @@ import com.pinterest.deployservice.bean.EnvironBean; import com.pinterest.deployservice.bean.EnvironState; import com.pinterest.deployservice.bean.ExternalAlert; -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; import com.pinterest.deployservice.dao.EnvironDAO; import com.pinterest.deployservice.handler.DeployHandler; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.Authorizer; - +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; import com.google.common.collect.ImmutableMap; + import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.apache.commons.lang.StringUtils; @@ -47,6 +47,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; + +import javax.annotation.security.RolesAllowed; import javax.ws.rs.Consumes; import javax.ws.rs.POST; import javax.ws.rs.Path; @@ -68,7 +70,6 @@ public class EnvAlerts { private EnvironDAO environDAO; private DeployHandler deployHandler; - private Authorizer authorizer; private ExternalAlertFactory externalAlertFactory; private ServiceContext serviceContext; private Map supportActions; @@ -76,7 +77,6 @@ public class EnvAlerts { public EnvAlerts(@Context TeletraanServiceContext context) { environDAO = context.getEnvironDAO(); - authorizer = context.getAuthorizer(); externalAlertFactory = context.getExternalAlertsFactory(); deployHandler = new DeployHandler(context); supportActions = new ImmutableMap.Builder() @@ -101,6 +101,8 @@ public void setAlertContextBuilder( value = "The alert response", notes = "Return the alert checking result", response = Response.class) + @RolesAllowed(TeletraanPrincipalRoles.Names.EXECUTE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = ResourceAuthZInfo.Location.PATH) /** * This method is supposed to be triggered by the alerting system from a webhook. It means * the environment has received an alert @@ -114,8 +116,6 @@ public Response alertsTriggered(@PathParam("envName") String envName, @Context SecurityContext sc, String alertBody) throws Exception { EnvironBean environBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer - .authorize(sc, new Resource(environBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String userName = sc.getUserPrincipal().getName(); LOG.info("Get Alert for env {} stage {} actionWindow {} actions {} with alert body {}", envName, stageName, actionWindow, actions, alertBody); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvCapacities.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvCapacities.java index 32bb54efae..d9e46b3fae 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvCapacities.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvCapacities.java @@ -16,21 +16,23 @@ package com.pinterest.teletraan.resource; import com.pinterest.deployservice.bean.EnvironBean; -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; import com.pinterest.deployservice.common.Constants; import com.pinterest.deployservice.dao.EnvironDAO; import com.pinterest.deployservice.dao.GroupDAO; import com.pinterest.deployservice.handler.ConfigHistoryHandler; import com.pinterest.deployservice.handler.EnvironHandler; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.Authorizer; - +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; import com.google.common.base.Optional; + import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.apache.commons.lang3.StringUtils; import javax.validation.constraints.NotEmpty; + +import javax.annotation.security.RolesAllowed; import javax.validation.constraints.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,14 +63,12 @@ public class EnvCapacities { private ConfigHistoryHandler configHistoryHandler; private EnvironDAO environDAO; private GroupDAO groupDAO; - private Authorizer authorizer; public EnvCapacities(@Context TeletraanServiceContext context) { environHandler = new EnvironHandler(context); configHistoryHandler = new ConfigHistoryHandler(context); environDAO = context.getEnvironDAO(); groupDAO = context.getGroupDAO(); - authorizer = context.getAuthorizer(); } @GET @@ -91,12 +91,13 @@ public List get(@PathParam("envName") String envName, @ApiOperation( value = "Update the capacities for Group and hosts", notes = "Update the capacities for Group and hosts") + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = ResourceAuthZInfo.Location.PATH) public void update(@PathParam("envName") String envName, @PathParam("stageName") String stageName, @QueryParam("capacityType") Optional capacityType, @NotNull List names, @Context SecurityContext sc) throws Exception { EnvironBean envBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(envBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String operator = sc.getUserPrincipal().getName(); if (capacityType.or(CapacityType.GROUP) == CapacityType.GROUP) { environHandler.updateGroups(envBean, names, operator); @@ -121,12 +122,13 @@ public void update(@PathParam("envName") String envName, @ApiOperation( value = "Create the capacities for Group and hosts", notes = "Create the capacities for Group and hosts") + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = ResourceAuthZInfo.Location.PATH) public void add(@PathParam("envName") String envName, @PathParam("stageName") String stageName, @QueryParam("capacityType") Optional capacityType, @NotEmpty String name, @Context SecurityContext sc) throws Exception { EnvironBean envBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(envBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String operator = sc.getUserPrincipal().getName(); name = name.replaceAll("\"", ""); if (capacityType.or(CapacityType.GROUP) == CapacityType.GROUP) { @@ -142,12 +144,13 @@ public void add(@PathParam("envName") String envName, @ApiOperation( value = "Delete the capacities for Group and hosts", notes = "Delete the capacities for Group and hosts") + @RolesAllowed(TeletraanPrincipalRoles.Names.DELETE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = ResourceAuthZInfo.Location.PATH) public void delete(@PathParam("envName") String envName, @PathParam("stageName") String stageName, @QueryParam("capacityType") Optional capacityType, @NotEmpty String name, @Context SecurityContext sc) throws Exception { EnvironBean envBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(envBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String operator = sc.getUserPrincipal().getName(); name = name.replaceAll("\"", ""); if (capacityType.or(CapacityType.GROUP) == CapacityType.GROUP) { diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvDeploys.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvDeploys.java index 16bce6bde2..cbeca95c29 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvDeploys.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvDeploys.java @@ -22,19 +22,21 @@ import com.pinterest.deployservice.common.Constants; import com.pinterest.deployservice.dao.DeployDAO; import com.pinterest.deployservice.dao.EnvironDAO; -import com.pinterest.deployservice.dao.BuildDAO; import com.pinterest.deployservice.dao.AgentDAO; import com.pinterest.deployservice.handler.ConfigHistoryHandler; import com.pinterest.deployservice.handler.DeployHandler; import com.pinterest.deployservice.handler.EnvironHandler; import com.pinterest.teletraan.TeletraanServiceContext; import com.pinterest.deployservice.exception.TeletaanInternalException; -import com.pinterest.teletraan.security.Authorizer; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import javax.validation.constraints.NotEmpty; + +import javax.annotation.security.RolesAllowed; import javax.validation.constraints.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,9 +63,7 @@ public enum HostActions { private static final Logger LOG = LoggerFactory.getLogger(EnvDeploys.class); private EnvironDAO environDAO; - private BuildDAO buildDAO; private DeployDAO deployDAO; - private Authorizer authorizer; private AgentDAO agentDAO; private EnvironHandler environHandler; private DeployHandler deployHandler; @@ -71,9 +71,7 @@ public enum HostActions { public EnvDeploys(@Context TeletraanServiceContext context) throws Exception { environDAO = context.getEnvironDAO(); - buildDAO = context.getBuildDAO(); deployDAO = context.getDeployDAO(); - authorizer = context.getAuthorizer(); agentDAO = context.getAgentDAO(); environHandler = new EnvironHandler(context); deployHandler = new DeployHandler(context); @@ -103,6 +101,8 @@ public DeployBean get( value = "Take deploy action", notes = "Take an action on a deploy such as RESTART or PAUSE", response = Response.class) + @RolesAllowed(TeletraanPrincipalRoles.Names.EXECUTE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = ResourceAuthZInfo.Location.PATH) public Response action( @Context SecurityContext sc, @Context UriInfo uriInfo, @@ -113,7 +113,6 @@ public Response action( @ApiParam(value = "Upper bound deploy id", required = true)@QueryParam("toDeployId") String toDeployId, @ApiParam(value = "Description", required = true)@QueryParam("description") String description) throws Exception { EnvironBean envBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(envBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String operator = sc.getUserPrincipal().getName(); String newDeployId; switch (actionType) { @@ -153,6 +152,9 @@ public Response action( value = "Take a deploy action", notes = "Take an action on a deploy using host information", response = Response.class) + @RolesAllowed(TeletraanPrincipalRoles.Names.EXECUTE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = ResourceAuthZInfo.Location.PATH) + // TODO: sidecar owners can perform actions on non-sidecar agents public void update( @Context SecurityContext sc, @ApiParam(value = "Environment name", required = true)@PathParam("envName") String envName, @@ -160,7 +162,6 @@ public void update( @ApiParam(value = "Agent object to update with", required = true)@NotNull @QueryParam("actionType") HostActions actionType, @NotNull List hostIds) throws Exception { EnvironBean envBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(envBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); AgentBean agentBean = new AgentBean(); switch (actionType) { case PAUSED_BY_USER: @@ -193,6 +194,8 @@ public void update( value = "Create a deploy", notes = "Creates a deploy given an environment name, stage name, build id and description", response = Response.class) + @RolesAllowed(TeletraanPrincipalRoles.Names.EXECUTE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = ResourceAuthZInfo.Location.PATH) public Response create( @Context SecurityContext sc, @Context UriInfo uriInfo, @@ -202,7 +205,6 @@ public Response create( @ApiParam(value = "Description", required = true)@QueryParam("description") String description, @ApiParam(value = "Delivery type", required = false)@QueryParam("deliveryType") String deliveryType) throws Exception { EnvironBean envBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(envBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String operator = sc.getUserPrincipal().getName(); String deployId = deployHandler.deploy(envBean, buildId, description, deliveryType, operator); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvGroupRoles.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvGroupRoles.java index 41515d4dd8..561502ff7c 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvGroupRoles.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvGroupRoles.java @@ -4,9 +4,9 @@ * 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. @@ -16,10 +16,14 @@ package com.pinterest.teletraan.resource; import com.pinterest.deployservice.bean.GroupRolesBean; -import com.pinterest.deployservice.bean.Resource; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; import com.pinterest.teletraan.TeletraanServiceContext; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import io.swagger.annotations.*; +import javax.annotation.security.RolesAllowed; import javax.validation.Valid; import javax.ws.rs.*; import javax.ws.rs.core.*; @@ -36,7 +40,7 @@ @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public class EnvGroupRoles extends GroupRoles { - private static final Resource.Type RESOURCE_TYPE = Resource.Type.ENV; + private static final AuthZResource.Type RESOURCE_TYPE = AuthZResource.Type.ENV; public EnvGroupRoles(@Context TeletraanServiceContext context) { super(context); @@ -69,10 +73,11 @@ public GroupRolesBean getByNameAndResource(@PathParam("envName") String envName, value = "Update an environment's group role", notes = "Updates a GroupRoles object for given group and environment names with given GroupRoles object.", response = GroupRolesBean.class) - public void update(@Context SecurityContext sc, @PathParam("envName") String envName, - @PathParam("groupName") String groupName, - GroupRolesBean bean) throws Exception { - super.update(sc, bean, groupName, envName, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV, idLocation = ResourceAuthZInfo.Location.PATH) + public void update(@PathParam("envName") String envName, @PathParam("groupName") String groupName, + GroupRolesBean bean) throws Exception { + super.update(bean, groupName, envName, RESOURCE_TYPE); } @POST @@ -80,11 +85,12 @@ public void update(@Context SecurityContext sc, @PathParam("envName") String env value = "Create a group role for an environment", notes = "Creates a new GroupRoles object for a given environment name.", response = Response.class) - public Response create(@Context SecurityContext sc, - @Context UriInfo uriInfo, - @ApiParam(value = "Environment name.", required = true)@PathParam("envName") String envName, - @ApiParam(value = "GroupRolesBean object.", required = true)@Valid GroupRolesBean bean) throws Exception { - return super.create(sc, uriInfo, bean, envName, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV, idLocation = ResourceAuthZInfo.Location.PATH) + public Response create(@Context UriInfo uriInfo, + @ApiParam(value = "Environment name.", required = true) @PathParam("envName") String envName, + @ApiParam(value = "GroupRolesBean object.", required = true)@Valid GroupRolesBean bean) throws Exception { + return super.create(uriInfo, bean, envName, RESOURCE_TYPE); } @DELETE @@ -92,8 +98,10 @@ public Response create(@Context SecurityContext sc, @ApiOperation( value = "Deletes a group role from an environment", notes = "Deletes a GroupRoles object by given group and environment names.") - public void delete(@Context SecurityContext sc, @PathParam("envName") String envName, - @PathParam("groupName") String groupName) throws Exception { - super.delete(sc, groupName, envName, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.DELETE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV, idLocation = ResourceAuthZInfo.Location.PATH) + public void delete(@PathParam("envName") String envName, + @PathParam("groupName") String groupName) throws Exception { + super.delete(groupName, envName, RESOURCE_TYPE); } } diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvHostTags.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvHostTags.java index 00e64f427e..151e314f4c 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvHostTags.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvHostTags.java @@ -7,7 +7,10 @@ import com.pinterest.deployservice.dao.HostTagDAO; import com.pinterest.deployservice.rodimus.RodimusManager; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.Authorizer; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo.Location; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.SwaggerDefinition; @@ -15,6 +18,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.security.RolesAllowed; import javax.ws.rs.*; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; @@ -37,14 +41,12 @@ public class EnvHostTags { private EnvironDAO environDAO; private HostDAO hostDAO; private final RodimusManager rodimusManager; - private Authorizer authorizer; public EnvHostTags(@Context TeletraanServiceContext context) { hostDAO = context.getHostDAO(); hostTagDAO = context.getHostTagDAO(); environDAO = context.getEnvironDAO(); - authorizer = context.getAuthorizer(); rodimusManager = context.getRodimusManager(); } @@ -54,12 +56,13 @@ public EnvHostTags(@Context TeletraanServiceContext context) { value = "List all the hosts tags", notes = "Returns a list the host tags in an environment", response = HostTagInfo.class) + @RolesAllowed(TeletraanPrincipalRoles.Names.EXECUTE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = Location.PATH) public Collection get(@PathParam("envName") String envName, @PathParam("stageName") String stageName, @QueryParam("ec2Tags") Optional ecTags, @Context SecurityContext sc) throws Exception { EnvironBean envBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(envBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); Boolean loadEc2Tags = ecTags.or(false); if (loadEc2Tags) { @@ -77,13 +80,14 @@ public Collection get(@PathParam("envName") String envName, value = "List all the hosts that are tagged with tagName in an environment, and group by tagValue", notes = "Returns a map group by tagValue and hosts tagged with tagName:tagValue in an environment", response = HostTagInfo.class) + @RolesAllowed(TeletraanPrincipalRoles.Names.EXECUTE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = Location.PATH) public Map> get(@PathParam("envName") String envName, @PathParam("stageName") String stageName, @PathParam("tagName") String tagName, @QueryParam("ec2Tags") Optional ecTags, @Context SecurityContext sc) throws Exception { EnvironBean envBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(envBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); Boolean loadEc2Tags = ecTags.or(false); if (loadEc2Tags) { @@ -105,13 +109,13 @@ public Map> get(@PathParam("envName") String env @DELETE @Path("/{tagName : [a-zA-Z0-9\\-:_]+}") + @RolesAllowed(TeletraanPrincipalRoles.Names.DELETE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = Location.PATH) public void removeHostTags(@PathParam("envName") String envName, @PathParam("stageName") String stageName, @PathParam("tagName") String tagName, @Context SecurityContext sc) throws Exception { - EnvironBean envBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(envBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String envId = envBean.getEnv_id(); hostTagDAO.deleteAllByEnvId(envId, tagName); LOG.info("Successfully removed all host tagged by {} in env {}", tagName, envId); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvHosts.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvHosts.java index f9f6463d1f..881299290c 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvHosts.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvHosts.java @@ -20,15 +20,16 @@ import com.google.common.base.Optional; import com.pinterest.deployservice.bean.EnvironBean; import com.pinterest.deployservice.bean.HostBean; -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; import com.pinterest.deployservice.common.Constants; import com.pinterest.deployservice.dao.EnvironDAO; import com.pinterest.deployservice.dao.HostDAO; import com.pinterest.deployservice.handler.ConfigHistoryHandler; import com.pinterest.deployservice.handler.EnvironHandler; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.Authorizer; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo.Location; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -37,6 +38,8 @@ import org.slf4j.LoggerFactory; import java.util.Collection; + +import javax.annotation.security.RolesAllowed; import javax.validation.Valid; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; @@ -55,14 +58,12 @@ @Consumes(MediaType.APPLICATION_JSON) public class EnvHosts { private static final Logger LOG = LoggerFactory.getLogger(EnvHosts.class); - private final Authorizer authorizer; private final EnvironDAO environDAO; private final HostDAO hostDAO; private final EnvironHandler environHandler; private final ConfigHistoryHandler configHistoryHandler; public EnvHosts(@Context TeletraanServiceContext context) { - authorizer = context.getAuthorizer(); environDAO = context.getEnvironDAO(); hostDAO = context.getHostDAO(); environHandler = new EnvironHandler(context); @@ -96,6 +97,9 @@ public Collection getHostByHostName( } @DELETE + @RolesAllowed(TeletraanPrincipalRoles.Names.DELETE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = Location.PATH) + // TODO: this allows sidecar owners to stop hosts public void stopServiceOnHost(@Context SecurityContext sc, @PathParam("envName") String envName, @PathParam("stageName") String stageName, @@ -104,7 +108,6 @@ public void stopServiceOnHost(@Context SecurityContext sc, throws Exception { String operator = sc.getUserPrincipal().getName(); EnvironBean envBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(envBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); environHandler.stopServiceOnHosts(hostIds, replaceHost.or(true)); configHistoryHandler.updateConfigHistory(envBean.getEnv_id(), Constants.TYPE_HOST_ACTION, String.format("STOP %s", hostIds.toString()), operator); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvMetrics.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvMetrics.java index f7cc961ef1..00a9198557 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvMetrics.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvMetrics.java @@ -4,9 +4,9 @@ * 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. @@ -17,20 +17,23 @@ import com.pinterest.deployservice.bean.EnvironBean; import com.pinterest.deployservice.bean.MetricsConfigBean; -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; import com.pinterest.deployservice.common.Constants; import com.pinterest.deployservice.dao.EnvironDAO; import com.pinterest.deployservice.handler.ConfigHistoryHandler; import com.pinterest.deployservice.handler.EnvironHandler; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.Authorizer; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo.Location; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.security.RolesAllowed; import javax.validation.Valid; import javax.ws.rs.*; import javax.ws.rs.core.Context; @@ -47,13 +50,11 @@ public class EnvMetrics { private EnvironHandler environHandler; private ConfigHistoryHandler configHistoryHandler; private EnvironDAO environDAO; - private Authorizer authorizer; public EnvMetrics(@Context TeletraanServiceContext context) { environDAO = context.getEnvironDAO(); environHandler = new EnvironHandler(context); configHistoryHandler = new ConfigHistoryHandler(context); - authorizer = context.getAuthorizer(); } @GET @@ -74,13 +75,14 @@ public List get( value = "Update environment metrics", notes = "Updates an environment's metrics configs given an environment name, stage name, and list of " + "MetricsConfig objects to update with") + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = Location.PATH) public void update( @ApiParam(value = "Environment name", required = true)@PathParam("envName") String envName, @ApiParam(value = "Stage name", required = true)@PathParam("stageName") String stageName, @ApiParam(value = "List of MetricsConfigBean objects", required = true)@Valid List metrics, @Context SecurityContext sc) throws Exception { EnvironBean environBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(environBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String userName = sc.getUserPrincipal().getName(); environHandler.updateMetrics(environBean, metrics, userName); configHistoryHandler.updateConfigHistory(environBean.getEnv_id(), Constants.TYPE_ENV_METRIC, metrics, userName); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvPromotes.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvPromotes.java index 8887ae8549..5abe826d80 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvPromotes.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvPromotes.java @@ -17,20 +17,23 @@ import com.pinterest.deployservice.bean.EnvironBean; import com.pinterest.deployservice.bean.PromoteBean; -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; import com.pinterest.deployservice.common.Constants; import com.pinterest.deployservice.dao.EnvironDAO; import com.pinterest.deployservice.handler.ConfigHistoryHandler; import com.pinterest.deployservice.handler.EnvironHandler; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.Authorizer; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo.Location; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.security.RolesAllowed; import javax.validation.Valid; import javax.ws.rs.*; import javax.ws.rs.core.Context; @@ -46,13 +49,11 @@ public class EnvPromotes { private EnvironHandler environHandler; private ConfigHistoryHandler configHistoryHandler; private EnvironDAO environDAO; - private Authorizer authorizer; public EnvPromotes(@Context TeletraanServiceContext context) { environDAO = context.getEnvironDAO(); environHandler = new EnvironHandler(context); configHistoryHandler = new ConfigHistoryHandler(context); - authorizer = context.getAuthorizer(); } @GET @@ -70,13 +71,14 @@ public PromoteBean get(@ApiParam(value = "Environment name", required = true)@Pa @ApiOperation( value = "Update promote info", notes = "Updates promote info given environment and stage names by given promote info object") + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = Location.PATH) public void update(@Context SecurityContext sc, @ApiParam(value = "Environment name", required = true) @PathParam("envName") String envName, @ApiParam(value = "Stage name", required = true) @PathParam("stageName") String stageName, @ApiParam(value = "Promote object to update with", required = true) @Valid PromoteBean promoteBean) throws Exception { EnvironBean environBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(environBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String operator = sc.getUserPrincipal().getName(); environHandler.updateEnvPromote(environBean, promoteBean, operator); configHistoryHandler.updateConfigHistory(environBean.getEnv_id(), Constants.TYPE_ENV_PROMOTE, promoteBean, operator); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvScriptConfigs.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvScriptConfigs.java index 7c48f67f07..8f945ed0cb 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvScriptConfigs.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvScriptConfigs.java @@ -4,9 +4,9 @@ * 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. @@ -16,20 +16,23 @@ package com.pinterest.teletraan.resource; import com.pinterest.deployservice.bean.EnvironBean; -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; import com.pinterest.deployservice.common.Constants; import com.pinterest.deployservice.dao.EnvironDAO; import com.pinterest.deployservice.handler.ConfigHistoryHandler; import com.pinterest.deployservice.handler.EnvironHandler; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.Authorizer; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo.Location; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.security.RolesAllowed; import javax.validation.Valid; import javax.ws.rs.*; import javax.ws.rs.core.Context; @@ -46,13 +49,11 @@ public class EnvScriptConfigs { private EnvironDAO environDAO; private EnvironHandler environHandler; private ConfigHistoryHandler configHistoryHandler; - private Authorizer authorizer; public EnvScriptConfigs(@Context TeletraanServiceContext context) { environDAO = context.getEnvironDAO(); environHandler = new EnvironHandler(context); configHistoryHandler = new ConfigHistoryHandler(context); - authorizer = context.getAuthorizer(); } @GET @@ -73,13 +74,14 @@ public Map get( notes = "Updates script configs given environment and stage names with given name:value map of new " + "script configs", response = String.class, responseContainer = "Map") + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = Location.PATH) public void update(@Context SecurityContext sc, @ApiParam(value = "Environment name", required = true)@PathParam("envName") String envName, @ApiParam(value = "Stage name", required = true)@PathParam("stageName") String stageName, @ApiParam(value = "New configs to update with", required = true) @Valid Map configs) throws Exception { EnvironBean envBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(envBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String operator = sc.getUserPrincipal().getName(); environHandler.updateScriptConfigs(envBean, configs, operator); configHistoryHandler.updateConfigHistory(envBean.getEnv_id(), Constants.TYPE_ENV_SCRIPT, configs, operator); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvStages.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvStages.java index 44cbe8ff8e..bddaef461e 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvStages.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvStages.java @@ -15,39 +15,50 @@ */ package com.pinterest.teletraan.resource; +import java.util.UUID; + +import javax.annotation.security.RolesAllowed; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.SecurityContext; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.pinterest.deployservice.bean.EnvType; import com.pinterest.deployservice.bean.EnvironBean; -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; import com.pinterest.deployservice.bean.TagBean; import com.pinterest.deployservice.bean.TagTargetType; import com.pinterest.deployservice.bean.TagValue; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; import com.pinterest.deployservice.common.Constants; import com.pinterest.deployservice.dao.EnvironDAO; +import com.pinterest.deployservice.exception.TeletaanInternalException; import com.pinterest.deployservice.handler.ConfigHistoryHandler; import com.pinterest.deployservice.handler.EnvTagHandler; import com.pinterest.deployservice.handler.EnvironHandler; import com.pinterest.deployservice.handler.TagHandler; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.deployservice.exception.TeletaanInternalException; -import com.pinterest.teletraan.security.Authorizer; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo.Location; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.ws.rs.*; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.SecurityContext; - -import java.util.UUID; - @Path("/v1/envs/{envName : [a-zA-Z0-9\\-_]+}/{stageName : [a-zA-Z0-9\\-_]+}") @Api(tags = "Environments") @Produces(MediaType.APPLICATION_JSON) @@ -63,14 +74,13 @@ public enum ActionType { private EnvironHandler environHandler; private ConfigHistoryHandler configHistoryHandler; private TagHandler tagHandler; - private Authorizer authorizer; + public EnvStages(@Context TeletraanServiceContext context) throws Exception { environDAO = context.getEnvironDAO(); environHandler = new EnvironHandler(context); configHistoryHandler = new ConfigHistoryHandler(context); tagHandler = new EnvTagHandler(context); - authorizer = context.getAuthorizer(); } @GET @@ -88,21 +98,25 @@ public EnvironBean get( @ApiOperation( value = "Update an environment", notes = "Update an environment given environment and stage names with a environment object") + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = Location.PATH) public void update(@Context SecurityContext sc, @ApiParam(value = "Environment name", required = true)@PathParam("envName") String envName, @ApiParam(value = "Stage name", required = true)@PathParam("stageName") String stageName, @ApiParam(value = "Desired Environment object with updates", required = true) EnvironBean environBean) throws Exception { - EnvironBean origBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(origBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); - // We must use default null Boolean to know that the user did not change from true->false - if (environBean.getIs_sox() != null && origBean.getIs_sox() != environBean.getIs_sox()) { - authorizer.authorize(sc, new Resource(Resource.ALL, Resource.Type.SYSTEM), Role.ADMIN); - } - // TODO: If is_sox is not provided, set it, this support existing PATCH style usages of the endpoint + final EnvironBean origBean = Utils.getEnvStage(environDAO, envName, stageName); + + // TODO: add test coverage + // treat null as false + Boolean originalIsSox = origBean.getIs_sox() != null ? origBean.getIs_sox() : false; + if (environBean.getIs_sox() == null) { - environBean.setIs_sox(origBean.getIs_sox()); + environBean.setIs_sox(originalIsSox); + } else if (originalIsSox != environBean.getIs_sox()) { + throw new TeletaanInternalException(Response.Status.FORBIDDEN, "Modification of isSox flag is not allowed!"); } + String operator = sc.getUserPrincipal().getName(); try { environBean.validate(); @@ -134,16 +148,36 @@ public void update(@Context SecurityContext sc, envName, stageName, environBean, operator); } + @PUT + @Path("/is-sox/{booleanValue}") + @ApiOperation( + value = "Update an environment/stage's isSox flag" + ) + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.SYSTEM, idLocation = Location.PATH) + public void updateIsSox(@Context SecurityContext sc, + @ApiParam(value = "Environment name", required = true)@PathParam("envName") String envName, + @ApiParam(value = "Stage name", required = true)@PathParam("stageName") String stageName, + @ApiParam(value = "Is sox flag", required = true)@PathParam("booleanValue") boolean isSox) throws Exception { + final EnvironBean origBean = Utils.getEnvStage(environDAO, envName, stageName); + origBean.setIs_sox(isSox); + String operator = sc.getUserPrincipal().getName(); + environHandler.updateStage(origBean, operator); + configHistoryHandler.updateConfigHistory(origBean.getEnv_id(), Constants.TYPE_ENV_GENERAL, origBean, operator); + configHistoryHandler.updateChangeFeed(Constants.CONFIG_TYPE_ENV, origBean.getEnv_id(), Constants.TYPE_ENV_GENERAL, operator, origBean.getExternal_id()); + LOG.info("Successfully updated env {}/{} isSox flag to {} by {}.", envName, stageName, isSox, operator); + } + @DELETE @ApiOperation( value = "Delete an environment", notes = "Deletes an environment given a environment and stage names") + @RolesAllowed(TeletraanPrincipalRoles.Names.DELETE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = Location.PATH) public void delete(@Context SecurityContext sc, @ApiParam(value = "Environment name", required = true)@PathParam("envName") String envName, @ApiParam(value = "Stage name", required = true)@PathParam("stageName") String stageName) throws Exception { - EnvironBean origBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(origBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String operator = sc.getUserPrincipal().getName(); environHandler.deleteEnvStage(envName, stageName, operator); LOG.info("Successfully deleted env {}/{} by {}.", envName, stageName, operator); @@ -156,6 +190,8 @@ public void delete(@Context SecurityContext sc, response = EnvironBean.class ) @Path("/external_id") + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = ResourceAuthZInfo.Location.PATH) public EnvironBean setExternalId( @ApiParam(value = "Environment name", required = true)@PathParam("envName") String envName, @ApiParam(value = "Stage name", required = true)@PathParam("stageName") String stageName, @@ -184,13 +220,14 @@ public EnvironBean setExternalId( @POST @Path("/actions") + @RolesAllowed(TeletraanPrincipalRoles.Names.EXECUTE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = Location.PATH) public void action(@Context SecurityContext sc, @PathParam("envName") String envName, @PathParam("stageName") String stageName, @NotNull @QueryParam("actionType") ActionType actionType, @NotEmpty @QueryParam("description") String description) throws Exception { EnvironBean envBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(envBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String operator = sc.getUserPrincipal().getName(); TagBean tagBean = new TagBean(); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvTokenRoles.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvTokenRoles.java index 5f02b2bec1..e03d93f880 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvTokenRoles.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvTokenRoles.java @@ -15,13 +15,17 @@ */ package com.pinterest.teletraan.resource; -import com.pinterest.deployservice.bean.Resource; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; import com.pinterest.deployservice.bean.TokenRolesBean; import com.pinterest.teletraan.TeletraanServiceContext; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; +import javax.annotation.security.RolesAllowed; import javax.validation.Valid; import javax.ws.rs.*; import javax.ws.rs.core.*; @@ -32,7 +36,7 @@ @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public class EnvTokenRoles extends TokenRoles { - private static final Resource.Type RESOURCE_TYPE = Resource.Type.ENV; + private static final AuthZResource.Type RESOURCE_TYPE = AuthZResource.Type.ENV; public EnvTokenRoles(@Context TeletraanServiceContext context) { super(context); @@ -43,9 +47,12 @@ public EnvTokenRoles(@Context TeletraanServiceContext context) { value = "Get environment TokenRoles objects", notes = "Returns all the TokenRoles objects for a given environment.", response = TokenRolesBean.class, responseContainer = "List") - public List getByResource(@Context SecurityContext sc, - @ApiParam(value = "Environment name.", required = true)@PathParam("envName") String envName) throws Exception { - return super.getByResource(sc, envName, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.READ) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV, idLocation = ResourceAuthZInfo.Location.PATH) + public List getByResource( + @ApiParam(value = "Environment name.", required = true) @PathParam("envName") String envName) + throws Exception { + return super.getByResource(envName, RESOURCE_TYPE); } @GET @@ -54,10 +61,12 @@ public List getByResource(@Context SecurityContext sc, value = "Get TokenRoles object by script and environment names", notes = "Returns a TokenRoles object given a script and environment name.", response = TokenRolesBean.class) - public TokenRolesBean getByNameAndResource(@Context SecurityContext sc, - @ApiParam(value = "Environment name.", required = true)@PathParam("envName") String envName, - @ApiParam(value = "Script name.", required = true)@PathParam("scriptName") String scriptName) throws Exception { - return super.getByNameAndResource(sc, scriptName, envName, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.READ) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV, idLocation = ResourceAuthZInfo.Location.PATH) + public TokenRolesBean getByNameAndResource( + @ApiParam(value = "Environment name.", required = true) @PathParam("envName") String envName, + @ApiParam(value = "Script name.", required = true) @PathParam("scriptName") String scriptName) throws Exception { + return super.getByNameAndResource(scriptName, envName, RESOURCE_TYPE); } @PUT @@ -65,10 +74,11 @@ public TokenRolesBean getByNameAndResource(@Context SecurityContext sc, @ApiOperation( value = "Update an envrionment's script token", notes = "Update a specific environment script token given environment and script names.") - public void update(@Context SecurityContext sc, - @ApiParam(value = "Environment name.", required = true)@PathParam("envName") String envName, - @ApiParam(value = "Script name.", required = true)@PathParam("scriptName") String scriptName, TokenRolesBean bean) throws Exception { - super.update(sc, bean, scriptName, envName, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV, idLocation = ResourceAuthZInfo.Location.PATH) + public void update(@ApiParam(value = "Environment name.", required = true) @PathParam("envName") String envName, + @ApiParam(value = "Script name.", required = true)@PathParam("scriptName") String scriptName, TokenRolesBean bean) throws Exception { + super.update(bean, scriptName, envName, RESOURCE_TYPE); } @POST @@ -76,11 +86,12 @@ public void update(@Context SecurityContext sc, value = "Create an environment script token", notes = "Creates an environment script token with given environment name and TokenRoles object.", response = Response.class) - public Response create(@Context SecurityContext sc, - @Context UriInfo uriInfo, - @ApiParam(value = "Environment name.", required = true)@PathParam("envName") String envName, - @ApiParam(value = "TokenRolesBean object.", required = true)@Valid TokenRolesBean bean) throws Exception { - return super.create(sc, uriInfo, bean, envName, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV, idLocation = ResourceAuthZInfo.Location.PATH) + public Response create(@Context UriInfo uriInfo, + @ApiParam(value = "Environment name.", required = true) @PathParam("envName") String envName, + @ApiParam(value = "TokenRolesBean object.", required = true)@Valid TokenRolesBean bean) throws Exception { + return super.create(uriInfo, bean, envName, RESOURCE_TYPE); } @DELETE @@ -88,9 +99,10 @@ public Response create(@Context SecurityContext sc, @ApiOperation( value = "Delete an environment script token", notes = "Deletes a script token by given environment and script name.") - public void delete(@Context SecurityContext sc, - @ApiParam(value = "Environment name.", required = true)@PathParam("envName") String envName, - @ApiParam(value = "Script name.", required = true)@PathParam("scriptName") String scriptName) throws Exception { - super.delete(sc, scriptName, envName, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.DELETE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV, idLocation = ResourceAuthZInfo.Location.PATH) + public void delete(@ApiParam(value = "Environment name.", required = true) @PathParam("envName") String envName, + @ApiParam(value = "Script name.", required = true)@PathParam("scriptName") String scriptName) throws Exception { + super.delete(scriptName, envName, RESOURCE_TYPE); } } diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvUserRoles.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvUserRoles.java index c78c1441ec..3cf1e032bb 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvUserRoles.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvUserRoles.java @@ -4,9 +4,9 @@ * 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. @@ -15,13 +15,15 @@ */ package com.pinterest.teletraan.resource; -import com.pinterest.deployservice.bean.Resource; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; import com.pinterest.deployservice.bean.UserRolesBean; import com.pinterest.teletraan.TeletraanServiceContext; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import io.swagger.annotations.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import javax.annotation.security.RolesAllowed; import javax.validation.Valid; import javax.ws.rs.*; import javax.ws.rs.core.*; @@ -37,10 +39,9 @@ @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public class EnvUserRoles extends UserRoles { - private static final Resource.Type RESOURCE_TYPE = Resource.Type.ENV; - private static final Logger LOG = LoggerFactory.getLogger(EnvUserRoles.class); + private static final AuthZResource.Type RESOURCE_TYPE = AuthZResource.Type.ENV; - public EnvUserRoles(@Context TeletraanServiceContext context) throws Exception { + public EnvUserRoles(@Context TeletraanServiceContext context) { super(context); } @@ -72,10 +73,11 @@ public UserRolesBean getByNameAndResource( value = "Update a user's environment role", notes = "Updates a UserRoles object for given user and environment names with given UserRoles object.", response = UserRolesBean.class) - public void update(@Context SecurityContext sc, - @ApiParam(value = "Environment name.", required = true)@PathParam("envName") String envName, - @ApiParam(value = "User name.", required = true)@PathParam("userName") String userName, UserRolesBean bean) throws Exception { - super.update(sc, bean, userName, envName, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV, idLocation = ResourceAuthZInfo.Location.PATH) + public void update(@ApiParam(value = "Environment name.", required = true) @PathParam("envName") String envName, + @ApiParam(value = "User name.", required = true)@PathParam("userName") String userName, UserRolesBean bean) throws Exception { + super.update(bean, userName, envName, RESOURCE_TYPE); } @POST @@ -83,11 +85,12 @@ public void update(@Context SecurityContext sc, value = "Create a user for an environment", notes = "Creates a new UserRoles object for a given environment name.", response = Response.class) - public Response create(@Context SecurityContext sc, - @Context UriInfo uriInfo, - @ApiParam(value = "Environment name.", required = true)@PathParam("envName") String envName, - @ApiParam(value = "UserRolesBean object.", required = true)@Valid UserRolesBean bean) throws Exception { - return super.create(sc, uriInfo, bean, envName, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV, idLocation = ResourceAuthZInfo.Location.PATH) + public Response create(@Context UriInfo uriInfo, + @ApiParam(value = "Environment name.", required = true) @PathParam("envName") String envName, + @ApiParam(value = "UserRolesBean object.", required = true)@Valid UserRolesBean bean) throws Exception { + return super.create(uriInfo, bean, envName, RESOURCE_TYPE); } @DELETE @@ -95,9 +98,10 @@ public Response create(@Context SecurityContext sc, @ApiOperation( value = "Deletes a user's roles from an environment", notes = "Deletes a UserRoles object by given user and environment names.") - public void delete(@Context SecurityContext sc, - @ApiParam(value = "Host name.", required = true)@PathParam("envName") String envName, - @PathParam("userName") String userName) throws Exception { - super.delete(sc, userName, envName, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.DELETE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV, idLocation = ResourceAuthZInfo.Location.PATH) + public void delete(@ApiParam(value = "Host name.", required = true) @PathParam("envName") String envName, + @PathParam("userName") String userName) throws Exception { + super.delete(userName, envName, RESOURCE_TYPE); } } diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvWebHooks.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvWebHooks.java index 805af8d566..6521f55c84 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvWebHooks.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/EnvWebHooks.java @@ -21,13 +21,17 @@ import com.pinterest.deployservice.handler.ConfigHistoryHandler; import com.pinterest.deployservice.handler.EnvironHandler; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.Authorizer; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo.Location; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.security.RolesAllowed; import javax.ws.rs.*; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; @@ -42,13 +46,11 @@ public class EnvWebHooks { private EnvironDAO environDAO; private EnvironHandler environHandler; private ConfigHistoryHandler configHistoryHandler; - private Authorizer authorizer; public EnvWebHooks(@Context TeletraanServiceContext context) { environDAO = context.getEnvironDAO(); environHandler = new EnvironHandler(context); configHistoryHandler = new ConfigHistoryHandler(context); - authorizer = context.getAuthorizer(); } @GET @@ -68,12 +70,13 @@ public EnvWebHookBean get( @ApiOperation( value = "Update webhooks", notes = "Updates pre/deploy webhooks by given environment and stage names with given webhooks object") + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = Location.PATH) public void update(@Context SecurityContext sc, @ApiParam(value = "Environment name", required = true)@PathParam("envName") String envName, @ApiParam(value = "Stage name", required = true)@PathParam("stageName") String stageName, EnvWebHookBean hookBean) throws Exception { EnvironBean environBean = Utils.getEnvStage(environDAO, envName, stageName); - authorizer.authorize(sc, new Resource(environBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); String userName = sc.getUserPrincipal().getName(); environHandler.updateHooks(environBean, hookBean, userName); configHistoryHandler.updateConfigHistory(environBean.getEnv_id(), Constants.TYPE_ENV_WEBHOOK, hookBean, userName); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Environs.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Environs.java index 6750a83067..4362a31608 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Environs.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Environs.java @@ -17,11 +17,10 @@ import com.google.common.base.Optional; import com.pinterest.deployservice.bean.EnvironBean; -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; import com.pinterest.deployservice.bean.TagBean; import com.pinterest.deployservice.bean.TagTargetType; import com.pinterest.deployservice.bean.TagValue; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; import com.pinterest.deployservice.bean.UserRolesBean; import com.pinterest.deployservice.dao.EnvironDAO; import com.pinterest.deployservice.dao.UserRolesDAO; @@ -30,8 +29,11 @@ import com.pinterest.deployservice.handler.TagHandler; import com.pinterest.teletraan.TeletraanServiceContext; import com.pinterest.deployservice.exception.TeletaanInternalException; -import com.pinterest.teletraan.security.Authorizer; -import com.pinterest.teletraan.security.OpenAuthorizer; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo.Location; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; +import com.pinterest.teletraan.universal.security.bean.UserPrincipal; + import io.swagger.annotations.*; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -40,6 +42,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.security.RolesAllowed; import javax.validation.Valid; import javax.ws.rs.*; import javax.ws.rs.core.*; @@ -70,14 +73,12 @@ public enum ActionType { private EnvironHandler environHandler; private TagHandler tagHandler; private UserRolesDAO userRolesDAO; - private final Authorizer authorizer; public Environs(@Context TeletraanServiceContext context) throws Exception { environDAO = context.getEnvironDAO(); environHandler = new EnvironHandler(context); tagHandler = new EnvTagHandler(context); userRolesDAO = context.getUserRolesDAO(); - authorizer = context.getAuthorizer(); } @GET @@ -144,28 +145,27 @@ public List getAll( value = "Create environment", notes = "Creates a new environment given an environment object", response = Response.class) + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV, idLocation = Location.BODY, beanClass = EnvironBean.class) public Response create( @Context SecurityContext sc, @Context UriInfo uriInfo, - @ApiParam(value = "Environemnt object to create in database", required = true)@Valid EnvironBean environBean) throws Exception { - String operator = sc.getUserPrincipal().getName(); - String envName = environBean.getEnv_name(); - List environBeans = environDAO.getByName(envName); - if (!CollectionUtils.isEmpty(environBeans)) { - authorizer.authorize(sc, new Resource(envName, Resource.Type.ENV), Role.OPERATOR); - } + @ApiParam(value = "Environment object to create in database", required = true)@Valid EnvironBean environBean) throws Exception { try { environBean.validate(); } catch (Exception e) { - throw new TeletaanInternalException(Response.Status.BAD_REQUEST, e.toString()); + throw new IllegalArgumentException(e); } + String operator = sc.getUserPrincipal().getName(); + String envName = environBean.getEnv_name(); + List environBeans = environDAO.getByName(envName); String id = environHandler.createEnvStage(environBean, operator); - if (!(authorizer instanceof OpenAuthorizer) && CollectionUtils.isEmpty(environBeans)) { + if (sc.getUserPrincipal() instanceof UserPrincipal && CollectionUtils.isEmpty(environBeans)) { // This is the first stage for this env, let's make operator ADMIN of this env UserRolesBean rolesBean = new UserRolesBean(); rolesBean.setResource_id(environBean.getEnv_name()); - rolesBean.setResource_type(Resource.Type.ENV); - rolesBean.setRole(Role.ADMIN); + rolesBean.setResource_type(AuthZResource.Type.ENV); + rolesBean.setRole(TeletraanPrincipalRoles.ADMIN); rolesBean.setUser_name(operator); userRolesDAO.insert(rolesBean); LOG.info("Make {} admin for the new env {}", operator, envName); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/GroupRoles.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/GroupRoles.java index 20f484b3dc..3b9a039751 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/GroupRoles.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/GroupRoles.java @@ -4,9 +4,9 @@ * 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. @@ -16,11 +16,9 @@ package com.pinterest.teletraan.resource; import com.pinterest.deployservice.bean.GroupRolesBean; -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; import com.pinterest.deployservice.dao.GroupRolesDAO; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.Authorizer; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; import javax.ws.rs.core.*; import java.net.URI; @@ -28,35 +26,28 @@ public abstract class GroupRoles { private final GroupRolesDAO groupRolesDAO; - private final Authorizer authorizer; - public GroupRoles(TeletraanServiceContext context) { + protected GroupRoles(TeletraanServiceContext context) { groupRolesDAO = context.getGroupRolesDAO(); - authorizer = context.getAuthorizer(); } public List getByResource(String resourceId, - Resource.Type resourceType) throws Exception { + AuthZResource.Type resourceType) throws Exception { return groupRolesDAO.getByResource(resourceId, resourceType); } public GroupRolesBean getByNameAndResource(String groupName, String resourceId, - Resource.Type resourceType) throws Exception { + AuthZResource.Type resourceType) throws Exception { return groupRolesDAO.getByNameAndResource(groupName, resourceId, resourceType); } - public void update(SecurityContext sc, GroupRolesBean bean, String groupName, - String resourceId, Resource.Type resourceType) throws Exception { - authorizer.authorize(sc, new Resource(resourceId, resourceType), Role.ADMIN); + public void update(GroupRolesBean bean, String groupName, String resourceId, AuthZResource.Type resourceType) + throws Exception { groupRolesDAO.update(bean, groupName, resourceId, resourceType); } - public Response create(SecurityContext sc, - UriInfo uriInfo, - GroupRolesBean bean, - String resourceId, - Resource.Type resourceType) throws Exception { - authorizer.authorize(sc, new Resource(resourceId, resourceType), Role.ADMIN); + public Response create(UriInfo uriInfo, GroupRolesBean bean, String resourceId, AuthZResource.Type resourceType) + throws Exception { bean.setResource_id(resourceId); bean.setResource_type(resourceType); groupRolesDAO.insert(bean); @@ -66,9 +57,7 @@ public Response create(SecurityContext sc, return Response.created(roleUri).entity(newBean).build(); } - public void delete(SecurityContext sc, String groupName, String resourceId, - Resource.Type resourceType) throws Exception { - authorizer.authorize(sc, new Resource(resourceId, resourceType), Role.ADMIN); + public void delete(String groupName, String resourceId, AuthZResource.Type resourceType) throws Exception { groupRolesDAO.delete(groupName, resourceId, resourceType); } } diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Hosts.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Hosts.java index 90e328f645..23a23a999b 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Hosts.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Hosts.java @@ -45,6 +45,7 @@ ) @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) +// TODO: CDP-7701 Add authorization to hosts endpoints public class Hosts { private static final Logger LOG = LoggerFactory.getLogger(Hosts.class); private HostDAO hostDAO; diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Hotfixs.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Hotfixs.java index 00624bca84..8ef83081ad 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Hotfixs.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Hotfixs.java @@ -4,9 +4,9 @@ * 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. @@ -23,10 +23,14 @@ import com.pinterest.deployservice.dao.HotfixDAO; import com.pinterest.teletraan.TeletraanServiceContext; import com.pinterest.deployservice.exception.TeletaanInternalException; -import com.pinterest.teletraan.security.Authorizer; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo.Location; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.security.RolesAllowed; import javax.validation.Valid; import javax.ws.rs.*; import javax.ws.rs.core.*; @@ -38,18 +42,16 @@ @Consumes(MediaType.APPLICATION_JSON) public class Hotfixs { private static final Logger LOG = LoggerFactory.getLogger(Hotfixs.class); - private final static int DEFAULT_TIME_OUT = 30; // minutes - private final static int DEFAULT_SIZE = 30; + private static final int DEFAULT_TIME_OUT = 30; // minutes + private static final int DEFAULT_SIZE = 30; private DeployDAO deployDAO; private BuildDAO buildDAO; private HotfixDAO hotfixDAO; - private final Authorizer authorizer; public Hotfixs(@Context TeletraanServiceContext context) { deployDAO = context.getDeployDAO(); buildDAO = context.getBuildDAO(); hotfixDAO = context.getHotfixDAO(); - authorizer = context.getAuthorizer(); } private HotfixBean getHotfixBean(String id) throws Exception { @@ -75,9 +77,9 @@ public List getAll(@QueryParam("envName") String envName, @PUT @Path("/{id : [a-zA-Z0-9\\-_]+}") - public void update(@Context SecurityContext sc, @PathParam("id") String id, + @RolesAllowed(TeletraanPrincipalRoles.Names.PUBLISH) + public void update(@PathParam("id") String id, HotfixBean hotfixBean) throws Exception { - authorizer.authorize(sc, new Resource(Resource.ALL, Resource.Type.SYSTEM), Role.PUBLISHER); hotfixDAO.update(id, hotfixBean); LOG.info("Successfully updated hotfix {} with {}.", id, hotfixBean); } @@ -92,10 +94,10 @@ private String generateJobName(String repo) { } @POST - public Response create(@Context SecurityContext sc, - @Context UriInfo uriInfo, - @Valid HotfixBean hotfixBean) throws Exception { - authorizer.authorize(sc, new Resource(hotfixBean.getEnv_name(), Resource.Type.ENV), Role.OPERATOR); + @RolesAllowed(TeletraanPrincipalRoles.Names.EXECUTE) + @ResourceAuthZInfo(type = AuthZResource.Type.ENV_STAGE, idLocation = Location.BODY, beanClass = HotfixBean.class) + public Response create(@Context SecurityContext sc, @Context UriInfo uriInfo, @Valid HotfixBean hotfixBean) + throws Exception { String hotfixId = CommonUtils.getBase64UUID(); hotfixBean.setId(hotfixId); hotfixBean.setState(HotfixState.INITIAL); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Pings.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Pings.java index 3d746c9c73..98f0570365 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Pings.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Pings.java @@ -4,9 +4,9 @@ * 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. @@ -19,17 +19,17 @@ import com.pinterest.deployservice.bean.PingRequestBean; import com.pinterest.deployservice.bean.PingResponseBean; import com.pinterest.deployservice.bean.PingResult; -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; import com.pinterest.deployservice.handler.PingHandler; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.Authorizer; + import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.security.RolesAllowed; import javax.validation.Valid; import javax.ws.rs.Consumes; import javax.ws.rs.POST; @@ -47,11 +47,9 @@ public class Pings { private static final Logger LOG = LoggerFactory.getLogger(Pings.class); private PingHandler pingHandler; - private final Authorizer authorizer; public Pings(@Context TeletraanServiceContext context) { pingHandler = new PingHandler(context); - authorizer = context.getAuthorizer(); } @POST @@ -60,11 +58,11 @@ public Pings(@Context TeletraanServiceContext context) { value = "Ping operation for agent ", notes = "Returns a deploy goal object given a ping request object", response = PingResponseBean.class) + @RolesAllowed(TeletraanPrincipalRoles.Names.PINGER) public PingResponseBean ping(@Context SecurityContext sc, @Context HttpHeaders headers, @ApiParam(value = "Ping request object", required = true)@Valid PingRequestBean requestBean) throws Exception { LOG.info("Receive ping request " + requestBean); - authorizer.authorize(sc, new Resource(Resource.ALL, Resource.Type.SYSTEM), Role.PINGER); boolean rate_limited = Boolean.parseBoolean(headers.getRequestHeaders().getFirst("x-envoy-low-watermark")); PingResult result= pingHandler.ping(requestBean, rate_limited); LOG.info("Send ping response " + result.getResponseBean()); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/SystemGroupRoles.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/SystemGroupRoles.java index c5596b37a2..731449504e 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/SystemGroupRoles.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/SystemGroupRoles.java @@ -4,9 +4,9 @@ * 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. @@ -16,14 +16,16 @@ package com.pinterest.teletraan.resource; import com.pinterest.deployservice.bean.GroupRolesBean; -import com.pinterest.deployservice.bean.Resource; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; import com.pinterest.teletraan.TeletraanServiceContext; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; +import javax.annotation.security.RolesAllowed; import javax.validation.Valid; import javax.ws.rs.*; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.SecurityContext; import javax.ws.rs.core.UriInfo; import java.util.List; @@ -31,8 +33,8 @@ @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public class SystemGroupRoles extends GroupRoles { - private final static Resource.Type RESOURCE_TYPE = Resource.Type.SYSTEM; - private final static String RESOURCE_ID = Resource.ALL; + private static final AuthZResource.Type RESOURCE_TYPE = AuthZResource.Type.SYSTEM; + private static final String RESOURCE_ID = AuthZResource.ALL; public SystemGroupRoles(@Context TeletraanServiceContext context) { super(context); @@ -51,19 +53,24 @@ public GroupRolesBean getByNameAndResource(@PathParam("groupName") String groupN @PUT @Path("/{groupName : [a-zA-Z0-9\\-_]+}") - public void update(@Context SecurityContext sc, @PathParam("groupName") String groupName, - GroupRolesBean bean) throws Exception { - super.update(sc, bean, groupName, RESOURCE_ID, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.SYSTEM) + public void update(@PathParam("groupName") String groupName, GroupRolesBean bean) throws Exception { + super.update(bean, groupName, RESOURCE_ID, RESOURCE_TYPE); } @POST - public void create(@Context SecurityContext sc, @Context UriInfo uriInfo, @Valid GroupRolesBean bean) throws Exception { - super.create(sc, uriInfo, bean, RESOURCE_ID, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.SYSTEM) + public void create(@Context UriInfo uriInfo, @Valid GroupRolesBean bean) throws Exception { + super.create(uriInfo, bean, RESOURCE_ID, RESOURCE_TYPE); } @DELETE @Path("/{groupName : [a-zA-Z0-9\\-_]+}") - public void delete(@Context SecurityContext sc, @PathParam("groupName") String groupName) throws Exception { - super.delete(sc, groupName, RESOURCE_ID, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.DELETE) + @ResourceAuthZInfo(type = AuthZResource.Type.SYSTEM) + public void delete(@PathParam("groupName") String groupName) throws Exception { + super.delete(groupName, RESOURCE_ID, RESOURCE_TYPE); } } diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/SystemTokenRoles.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/SystemTokenRoles.java index f80bf6b703..df7f156bf3 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/SystemTokenRoles.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/SystemTokenRoles.java @@ -4,9 +4,9 @@ * 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. @@ -15,11 +15,15 @@ */ package com.pinterest.teletraan.resource; -import com.pinterest.deployservice.bean.Resource; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; import com.pinterest.deployservice.bean.TokenRolesBean; import com.pinterest.teletraan.TeletraanServiceContext; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import io.swagger.annotations.*; +import javax.annotation.security.RolesAllowed; import javax.validation.Valid; import javax.ws.rs.*; import javax.ws.rs.core.*; @@ -35,8 +39,8 @@ @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public class SystemTokenRoles extends TokenRoles { - private static final Resource.Type RESOURCE_TYPE = Resource.Type.SYSTEM; - private final static String RESOURCE_ID = Resource.ALL; + private static final AuthZResource.Type RESOURCE_TYPE = AuthZResource.Type.SYSTEM; + private static final String RESOURCE_ID = AuthZResource.ALL; public SystemTokenRoles(TeletraanServiceContext context) { super(context); @@ -47,8 +51,10 @@ public SystemTokenRoles(TeletraanServiceContext context) { value = "Get system script tokens", notes = "Returns all system TokenRoles objects", response = TokenRolesBean.class, responseContainer = "List") - public List getByResource(@Context SecurityContext sc) throws Exception { - return super.getByResource(sc, RESOURCE_ID, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.READ) + @ResourceAuthZInfo(type = AuthZResource.Type.SYSTEM) + public List getByResource() throws Exception { + return super.getByResource(RESOURCE_ID, RESOURCE_TYPE); } @GET @@ -57,9 +63,12 @@ public List getByResource(@Context SecurityContext sc) throws Ex value = "Get system TokenRoles object by script name", notes = "Returns a TokenRoles object for given script name", response = TokenRolesBean.class) - public TokenRolesBean getByNameAndResource(@Context SecurityContext sc, - @ApiParam(value = "Script name.", required = true)@PathParam("scriptName") String scriptName) throws Exception { - return super.getByNameAndResource(sc, scriptName, RESOURCE_ID, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.READ) + @ResourceAuthZInfo(type = AuthZResource.Type.SYSTEM) + public TokenRolesBean getByNameAndResource( + @ApiParam(value = "Script name.", required = true) @PathParam("scriptName") String scriptName) + throws Exception { + return super.getByNameAndResource(scriptName, RESOURCE_ID, RESOURCE_TYPE); } @PUT @@ -67,10 +76,11 @@ public TokenRolesBean getByNameAndResource(@Context SecurityContext sc, @ApiOperation( value = "Update a system script token", notes = "Updates a TokenRoles object by given script name and replacement TokenRoles object") - public void update(@Context SecurityContext sc, - @ApiParam(value = "Script name.", required = true)@PathParam("scriptName") String scriptName, - @ApiParam(value = "TokenRolesBean object.", required = true)TokenRolesBean bean) throws Exception { - super.update(sc, bean, scriptName, RESOURCE_ID, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.SYSTEM) + public void update(@ApiParam(value = "Script name.", required = true) @PathParam("scriptName") String scriptName, + @ApiParam(value = "TokenRolesBean object.", required = true) TokenRolesBean bean) throws Exception { + super.update(bean, scriptName, RESOURCE_ID, RESOURCE_TYPE); } @POST @@ -78,10 +88,11 @@ public void update(@Context SecurityContext sc, value = "Create a system script token", notes = "Creates a specified system wide TokenRole and returns a Response object", response = Response.class) - public Response create(@Context SecurityContext sc, - @Context UriInfo uriInfo, - @ApiParam(value = "TokenRolesBean object.", required = true)@Valid TokenRolesBean bean) throws Exception { - return super.create(sc, uriInfo, bean, RESOURCE_ID, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.SYSTEM) + public Response create(@Context UriInfo uriInfo, + @ApiParam(value = "TokenRolesBean object.", required = true)@Valid TokenRolesBean bean) throws Exception { + return super.create(uriInfo, bean, RESOURCE_ID, RESOURCE_TYPE); } @DELETE @@ -89,8 +100,10 @@ public Response create(@Context SecurityContext sc, @ApiOperation( value = "Delete a system wide script token", notes = "Deletes a system wide TokenRoles object by specified script name") - public void delete(@Context SecurityContext sc, - @ApiParam(value = "Script name.", required = true)@PathParam("scriptName") String scriptName) throws Exception { - super.delete(sc, scriptName, RESOURCE_ID, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.DELETE) + @ResourceAuthZInfo(type = AuthZResource.Type.SYSTEM) + public void delete( + @ApiParam(value = "Script name.", required = true)@PathParam("scriptName") String scriptName) throws Exception { + super.delete(scriptName, RESOURCE_ID, RESOURCE_TYPE); } } diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/SystemUserRoles.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/SystemUserRoles.java index 6707dd616e..6b266e17e5 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/SystemUserRoles.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/SystemUserRoles.java @@ -4,9 +4,9 @@ * 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. @@ -15,13 +15,17 @@ */ package com.pinterest.teletraan.resource; -import com.pinterest.deployservice.bean.Resource; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; import com.pinterest.deployservice.bean.UserRolesBean; import com.pinterest.teletraan.TeletraanServiceContext; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; +import javax.annotation.security.RolesAllowed; import javax.validation.Valid; import javax.ws.rs.*; import javax.ws.rs.core.*; @@ -32,8 +36,8 @@ @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public class SystemUserRoles extends UserRoles { - private final static Resource.Type RESOURCE_TYPE = Resource.Type.SYSTEM; - private final static String RESOURCE_ID = Resource.ALL; + private static final AuthZResource.Type RESOURCE_TYPE = AuthZResource.Type.SYSTEM; + private static final String RESOURCE_ID = AuthZResource.ALL; public SystemUserRoles(TeletraanServiceContext context) { super(context); @@ -65,10 +69,11 @@ public UserRolesBean getByNameAndResource(@ApiParam(value = "Name of user", requ value = "Update a system level user's role", notes = "Updates a system level user's role given specified user name and replacement UserRoles object", response = UserRolesBean.class) - public void update(@Context SecurityContext sc, - @ApiParam(value = "Name of user.", required = true)@PathParam("userName") String userName, - @ApiParam(value = "UserRolesBean object", required = true)UserRolesBean bean) throws Exception { - super.update(sc, bean, userName, RESOURCE_ID, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.SYSTEM) + public void update(@ApiParam(value = "Name of user.", required = true) @PathParam("userName") String userName, + @ApiParam(value = "UserRolesBean object", required = true)UserRolesBean bean) throws Exception { + super.update(bean, userName, RESOURCE_ID, RESOURCE_TYPE); } @POST @@ -76,11 +81,11 @@ public void update(@Context SecurityContext sc, value = "Create a new system level user", notes = "Creates a system level user for given UserRoles object", response = Response.class) - public Response create(@Context SecurityContext sc, - @Context UriInfo uriInfo, - @ApiParam(value = "UserRolesBean object.", required = true) - @Valid UserRolesBean bean) throws Exception { - return super.create(sc, uriInfo, bean, RESOURCE_ID, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.WRITE) + @ResourceAuthZInfo(type = AuthZResource.Type.SYSTEM) + public Response create(@Context UriInfo uriInfo, + @ApiParam(value = "UserRolesBean object.", required = true) @Valid UserRolesBean bean) throws Exception { + return super.create(uriInfo, bean, RESOURCE_ID, RESOURCE_TYPE); } @DELETE @@ -88,9 +93,10 @@ public Response create(@Context SecurityContext sc, value = "Delete a system level user", notes = "Deletes a system level user by specified user name") @Path("/{userName : [a-zA-Z0-9\\-_]+}") - public void delete(@Context SecurityContext sc, - @ApiParam(value = "User name", required = true) - @PathParam("userName") String userName) throws Exception { - super.delete(sc, userName, RESOURCE_ID, RESOURCE_TYPE); + @RolesAllowed(TeletraanPrincipalRoles.Names.DELETE) + @ResourceAuthZInfo(type = AuthZResource.Type.SYSTEM) + public void delete( + @ApiParam(value = "User name", required = true) @PathParam("userName") String userName) throws Exception { + super.delete(userName, RESOURCE_ID, RESOURCE_TYPE); } } diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/TokenRoles.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/TokenRoles.java index c5b981ef49..702f63fd3b 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/TokenRoles.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/TokenRoles.java @@ -4,9 +4,9 @@ * 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. @@ -15,13 +15,12 @@ */ package com.pinterest.teletraan.resource; -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; import com.pinterest.deployservice.bean.TokenRolesBean; import com.pinterest.deployservice.common.CommonUtils; import com.pinterest.deployservice.dao.TokenRolesDAO; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.Authorizer; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,40 +30,32 @@ public abstract class TokenRoles { private static final Logger LOG = LoggerFactory.getLogger(TokenRoles.class); - final static public long VALIDATE_TIME = 10 * 365 * 24 * 60 * 60 * 1000L; + public static final long VALIDATE_TIME = 10 * 365 * 24 * 60 * 60 * 1000L; private final TokenRolesDAO tokenRolesDAO; - private final Authorizer authorizer; - public TokenRoles(TeletraanServiceContext context) { + protected TokenRoles(TeletraanServiceContext context) { tokenRolesDAO = context.getTokenRolesDAO(); - authorizer = context.getAuthorizer(); } - public List getByResource(SecurityContext sc, String resourceId, - Resource.Type resourceType) throws Exception { - authorizer.authorize(sc, new Resource(resourceId, resourceType), Role.ADMIN); + public List getByResource(String resourceId, + AuthZResource.Type resourceType) throws Exception { return tokenRolesDAO.getByResource(resourceId, resourceType); } - public TokenRolesBean getByNameAndResource(SecurityContext sc, String scriptName, - String resourceId, Resource.Type resourceType) throws Exception { - authorizer.authorize(sc, new Resource(resourceId, resourceType), Role.ADMIN); + public TokenRolesBean getByNameAndResource(String scriptName, + String resourceId, AuthZResource.Type resourceType) throws Exception { return tokenRolesDAO.getByNameAndResource(scriptName, resourceId, resourceType); } - public void update(SecurityContext sc, TokenRolesBean bean, String scriptName, - String resourceId, Resource.Type resourceType) throws Exception { - authorizer.authorize(sc, new Resource(resourceId, resourceType), Role.ADMIN); + public void update(TokenRolesBean bean, String scriptName, + String resourceId, AuthZResource.Type resourceType) throws Exception { tokenRolesDAO.update(bean, scriptName, resourceId, resourceType); LOG.info("Successfully updated script {} permission for resource {} with {}", scriptName, resourceId, bean); } - public Response create(SecurityContext sc, - UriInfo uriInfo, - TokenRolesBean bean, String resourceId, - Resource.Type resourceType) throws Exception { - authorizer.authorize(sc, new Resource(resourceId, resourceType), Role.ADMIN); + public Response create(UriInfo uriInfo, TokenRolesBean bean, String resourceId, + AuthZResource.Type resourceType) throws Exception { String token = CommonUtils.getBase64UUID(); bean.setToken(token); bean.setResource_id(resourceId); @@ -80,9 +71,8 @@ public Response create(SecurityContext sc, return Response.created(roleUri).entity(newBean).build(); } - public void delete(SecurityContext sc, String scriptName, String resourceId, - Resource.Type resourceType) throws Exception { - authorizer.authorize(sc, new Resource(resourceId, resourceType), Role.ADMIN); + public void delete(String scriptName, String resourceId, + AuthZResource.Type resourceType) throws Exception { tokenRolesDAO.delete(scriptName, resourceId, resourceType); LOG.info("Successfully deleted script {} permission for resource {}", scriptName, resourceId); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/UserRoles.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/UserRoles.java index 527f84391f..7bf00378ef 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/UserRoles.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/UserRoles.java @@ -4,9 +4,9 @@ * 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. @@ -18,9 +18,8 @@ import com.pinterest.deployservice.bean.UserRolesBean; import com.pinterest.deployservice.dao.UserRolesDAO; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.Authorizer; -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,37 +30,30 @@ public abstract class UserRoles { private static final Logger LOG = LoggerFactory.getLogger(UserRoles.class); private final UserRolesDAO userRolesDAO; - private final Authorizer authorizer; - public UserRoles(TeletraanServiceContext context) { + protected UserRoles(TeletraanServiceContext context) { userRolesDAO = context.getUserRolesDAO(); - authorizer = context.getAuthorizer(); } public List getByResource(String resourceId, - Resource.Type resourceType) throws Exception { + AuthZResource.Type resourceType) throws Exception { return userRolesDAO.getByResource(resourceId, resourceType); } public UserRolesBean getByNameAndResource(String userName, String resourceId, - Resource.Type resourceType) throws Exception { + AuthZResource.Type resourceType) throws Exception { return userRolesDAO.getByNameAndResource(userName, resourceId, resourceType); } - public void update(SecurityContext sc, UserRolesBean bean, String userName, - String resourceId, Resource.Type resourceType) throws Exception { - authorizer.authorize(sc, new Resource(resourceId, resourceType), Role.ADMIN); + public void update(UserRolesBean bean, String userName, String resourceId, AuthZResource.Type resourceType) + throws Exception { userRolesDAO.update(bean, userName, resourceId, resourceType); LOG.info("Successfully updated user {} permission for resource {} with {}", userName, resourceId, bean); } - public Response create(SecurityContext sc, - UriInfo uriInfo, - UserRolesBean bean, - String resourceId, - Resource.Type resourceType) throws Exception { - authorizer.authorize(sc, new Resource(resourceId, resourceType), Role.ADMIN); + public Response create(UriInfo uriInfo, UserRolesBean bean, String resourceId, AuthZResource.Type resourceType) + throws Exception { bean.setResource_id(resourceId); bean.setResource_type(resourceType); userRolesDAO.insert(bean); @@ -73,9 +65,7 @@ public Response create(SecurityContext sc, return Response.created(roleUri).entity(newBean).build(); } - public void delete(SecurityContext sc, String userName, String resourceId, - Resource.Type resourceType) throws Exception { - authorizer.authorize(sc, new Resource(resourceId, resourceType), Role.ADMIN); + public void delete(String userName, String resourceId, AuthZResource.Type resourceType) throws Exception { userRolesDAO.delete(userName, resourceId, resourceType); LOG.info("Successfully deleted user {} permission for resource {}", userName, resourceId); diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Utils.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Utils.java index 2911a39f76..0c3833e780 100644 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Utils.java +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/resource/Utils.java @@ -4,9 +4,9 @@ * 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. @@ -15,23 +15,18 @@ */ package com.pinterest.teletraan.resource; +import java.util.Map; + +import javax.ws.rs.core.Response; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.pinterest.deployservice.bean.DeployBean; import com.pinterest.deployservice.bean.EnvironBean; -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; import com.pinterest.deployservice.dao.DeployDAO; import com.pinterest.deployservice.dao.EnvironDAO; import com.pinterest.deployservice.exception.TeletaanInternalException; -import com.pinterest.teletraan.security.Authorizer; -import org.apache.commons.collections.CollectionUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.ws.rs.core.Response; -import javax.ws.rs.core.SecurityContext; -import java.util.Arrays; -import java.util.List; -import java.util.Map; public class Utils { private static final Logger LOG = LoggerFactory.getLogger(Utils.class); @@ -55,46 +50,6 @@ public static EnvironBean getEnvStage(EnvironDAO environDAO, String envId) throw return environBean; } - private static void authorizeEnvirons(List environBeans, - SecurityContext sc, Authorizer authorizer, Role role) throws Exception { - for (EnvironBean environBean : environBeans) { - try { - Resource resource = new Resource(environBean.getEnv_name(), Resource.Type.ENV); - authorizer.authorize(sc, resource, role); - return; - } catch (Exception e) { - // Not authorized, for whatever reason - LOG.info("Failed to authorize {} for resource {} and role {}", - sc.getUserPrincipal().getName(), environBean.getEnv_name(), role); - } - } - throw new TeletaanInternalException(Response.Status.FORBIDDEN, "Not authorized!"); - } - - public static void authorizeGroup(EnvironDAO environDAO, String groupName, - SecurityContext sc, Authorizer authorizer, Role role) throws Exception { - List environBeans = environDAO.getEnvsByGroups(Arrays.asList(groupName)); - if (CollectionUtils.isEmpty(environBeans)) { - // For groups not associate with environ yet, just pass it - LOG.warn("Group {} is not managed by Teletraan yet, authorize the action for now", - groupName); - return; - } - authorizeEnvirons(environBeans, sc, authorizer, role); - } - - public static void authorizeHost(EnvironDAO environDAO, String hostName, - SecurityContext sc, Authorizer authorizer, Role role) throws Exception { - List environBeans = environDAO.getEnvsByHost(hostName); - if (CollectionUtils.isEmpty(environBeans)) { - // For groups not associate with environ yet, just pass it - LOG.warn("Host {} is not managed by Teletraan yet, authorize the action for now", - hostName); - return; - } - authorizeEnvirons(environBeans, sc, authorizer, role); - } - public static DeployBean getDeploy(DeployDAO deployDAO, String deployId) throws Exception { DeployBean deployBean = deployDAO.getById(deployId); if (deployBean == null) { diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/AnonymousAuthFilter.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/AnonymousAuthFilter.java deleted file mode 100644 index 697cb9b32b..0000000000 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/AnonymousAuthFilter.java +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright 2016 Pinterest, 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.pinterest.teletraan.security; - -import javax.annotation.Priority; -import javax.ws.rs.Priorities; -import javax.ws.rs.container.ContainerRequestContext; -import javax.ws.rs.container.ContainerRequestFilter; -import javax.ws.rs.core.SecurityContext; -import javax.ws.rs.ext.Provider; -import java.io.IOException; -import java.security.Principal; - -@Provider -@Priority(Priorities.AUTHENTICATION) -public class AnonymousAuthFilter implements ContainerRequestFilter { - private static final AnonymousUser user = new AnonymousUser(); - private SecurityContext securityContext; - - public AnonymousAuthFilter() { - securityContext = new SecurityContext() { - - @Override - public Principal getUserPrincipal() { - return AnonymousAuthFilter.user; - } - - @Override - public boolean isUserInRole(String s) { - return true; - } - - @Override - public boolean isSecure() { - return true; - } - - @Override - public String getAuthenticationScheme() { - return "Anonymous"; - } - }; - } - - @Override - public void filter(ContainerRequestContext containerRequestContext) throws IOException { - containerRequestContext.setSecurityContext(securityContext); - } -} diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/AnonymousUser.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/AnonymousUser.java deleted file mode 100644 index b334e8ff54..0000000000 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/AnonymousUser.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright 2016 Pinterest, 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.pinterest.teletraan.security; - -import java.security.Principal; -import java.util.Collections; -import java.util.List; - -public class AnonymousUser implements Principal { - private String user; - private List groups; - - public AnonymousUser() { - this.user = "Anonymous"; - this.groups = Collections.emptyList(); - } - - @Override - public String getName() { - return user; - } - - public String getUser() { - return user; - } - - public List getGroups() { - return groups; - } -} diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/Authorizer.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/Authorizer.java deleted file mode 100644 index c1f0555712..0000000000 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/Authorizer.java +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright 2016 Pinterest, 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.pinterest.teletraan.security; - - -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; - -import javax.ws.rs.core.SecurityContext; - -public interface Authorizer { - void authorize(SecurityContext securityContext, Resource resource, Role requiredRole) throws Exception; -} diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/EnvPathExtractor.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/EnvPathExtractor.java new file mode 100644 index 0000000000..5d8f2ee21d --- /dev/null +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/EnvPathExtractor.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2024 Pinterest, 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.pinterest.teletraan.security; + +import com.pinterest.teletraan.universal.security.AuthZResourceExtractor; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; +import javax.ws.rs.container.ContainerRequestContext; + +public class EnvPathExtractor implements AuthZResourceExtractor { + @Override + public AuthZResource extractResource(ContainerRequestContext requestContext) + throws ExtractionException { + try { + String envName = requestContext.getUriInfo().getPathParameters().getFirst("envName"); + return new AuthZResource(envName, AuthZResource.Type.ENV); + } catch (Exception e) { + throw new ExtractionException("Failed to extract environment resource", e); + } + } +} diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/EnvStageBodyExtractor.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/EnvStageBodyExtractor.java new file mode 100644 index 0000000000..3706c87350 --- /dev/null +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/EnvStageBodyExtractor.java @@ -0,0 +1,109 @@ +/** + * Copyright (c) 2024 Pinterest, 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.pinterest.teletraan.security; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.pinterest.deployservice.ServiceContext; +import com.pinterest.deployservice.bean.AgentBean; +import com.pinterest.deployservice.bean.DeployBean; +import com.pinterest.deployservice.bean.EnvironBean; +import com.pinterest.deployservice.bean.HotfixBean; +import com.pinterest.deployservice.dao.EnvironDAO; +import com.pinterest.teletraan.universal.security.AuthZResourceExtractor; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; +import java.io.InputStream; +import javax.ws.rs.container.ContainerRequestContext; + +public class EnvStageBodyExtractor implements AuthZResourceExtractor { + private final EnvironDAO environDAO; + + public EnvStageBodyExtractor(ServiceContext context) { + this.environDAO = context.getEnvironDAO(); + } + + @Override + public AuthZResource extractResource(ContainerRequestContext requestContext, Class beanClass) + throws ExtractionException { + return extractResource(requestContext, beanClass, false); + } + + @Override + public AuthZResource extractResource(ContainerRequestContext requestContext) + throws ExtractionException { + return extractResource(requestContext, Object.class, true); + } + + AuthZResource extractResource(ContainerRequestContext requestContext, Class beanClass, boolean tryAll) + throws ExtractionException { + InputStream inputStream = requestContext.getEntityStream(); + if (beanClass.equals(EnvironBean.class) || tryAll) { + try { + EnvironBean envBean = new ObjectMapper().readValue(inputStream, EnvironBean.class); + return new AuthZResource(envBean.getEnv_name(), envBean.getStage_name()); + } catch (Exception e) { + if (!tryAll) { + throw new BeanClassExtractionException(beanClass, e); + } + } + } + + if (beanClass.equals(DeployBean.class) || tryAll) { + try { + DeployBean deployBean = new ObjectMapper().readValue(inputStream, DeployBean.class); + EnvironBean envBean = environDAO.getById(deployBean.getEnv_id()); + return new AuthZResource(envBean.getEnv_name(), envBean.getStage_name()); + } catch (Exception e) { + if (!tryAll) { + throw new BeanClassExtractionException(beanClass, e); + } + } + } + + if (beanClass.equals(HotfixBean.class) || tryAll) { + try { + HotfixBean hotfixBean = new ObjectMapper().readValue(inputStream, HotfixBean.class); + return new AuthZResource(hotfixBean.getEnv_name(), ""); + } catch (Exception e) { + if (!tryAll) { + throw new BeanClassExtractionException(beanClass, e); + } + } + } + + if (beanClass.equals(AgentBean.class) || tryAll) { + try { + AgentBean agentBean = new ObjectMapper().readValue(inputStream, AgentBean.class); + EnvironBean envBean = environDAO.getById(agentBean.getEnv_id()); + return new AuthZResource(envBean.getEnv_name(), envBean.getStage_name()); + } catch (Exception e) { + if (!tryAll) { + throw new BeanClassExtractionException(beanClass, e); + } + } + } + + if (tryAll) { + throw new ExtractionException("Failed to extract environment resource using all supported classes"); + } + throw new UnsupportedOperationException("Failed to extract environment resource"); + } + + class BeanClassExtractionException extends ExtractionException { + public BeanClassExtractionException(Class beanClass, Throwable cause) { + super(String.format("failed to extract as %s", beanClass.getName()), cause); + } + } +} diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/EnvStagePathExtractor.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/EnvStagePathExtractor.java new file mode 100644 index 0000000000..8ad92bcb21 --- /dev/null +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/EnvStagePathExtractor.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2024 Pinterest, 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.pinterest.teletraan.security; + +import com.pinterest.teletraan.universal.security.AuthZResourceExtractor; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; +import javax.ws.rs.container.ContainerRequestContext; + +public class EnvStagePathExtractor implements AuthZResourceExtractor { + @Override + public AuthZResource extractResource(ContainerRequestContext requestContext) + throws ExtractionException { + try { + String envName = requestContext.getUriInfo().getPathParameters().getFirst("envName"); + String stageName = + requestContext.getUriInfo().getPathParameters().getFirst("stageName"); + return new AuthZResource(envName, stageName); + } catch (Exception e) { + throw new ExtractionException("Failed to extract environment resource", e); + } + } +} diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/OpenAuthorizer.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/OpenAuthorizer.java deleted file mode 100644 index 3f63294cf2..0000000000 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/OpenAuthorizer.java +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright 2016 Pinterest, 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.pinterest.teletraan.security; - -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; - -import javax.ws.rs.core.SecurityContext; - -public class OpenAuthorizer implements Authorizer { - @Override - public void authorize(SecurityContext securityContext, Resource resource, Role requiredRole) throws Exception { - } -} diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/RoleAuthorizer.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/RoleAuthorizer.java deleted file mode 100644 index 6419bf1f2b..0000000000 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/RoleAuthorizer.java +++ /dev/null @@ -1,119 +0,0 @@ -/** - * Copyright 2016 Pinterest, 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.pinterest.teletraan.security; - -import com.pinterest.deployservice.ServiceContext; -import com.pinterest.deployservice.bean.*; -import com.pinterest.deployservice.dao.GroupRolesDAO; -import com.pinterest.deployservice.dao.UserRolesDAO; -import com.pinterest.deployservice.exception.TeletaanInternalException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.ws.rs.core.Response; -import javax.ws.rs.core.SecurityContext; -import java.util.*; - -public class RoleAuthorizer implements Authorizer { - private static final Logger LOG = LoggerFactory.getLogger(RoleAuthorizer.class); - private UserRolesDAO userRolesDAO; - private GroupRolesDAO groupRolesDAO; - - public RoleAuthorizer(ServiceContext context, String roleCacheSpec) throws Exception { - this.userRolesDAO = context.getUserRolesDAO(); - this.groupRolesDAO = context.getGroupRolesDAO(); - } - - public void checkUserPermission(String userName, Resource resource, List groups, Role requiredRole) throws Exception { - // Consider group role(s) - Set groupsSet = new HashSet<>(); - if(groups != null && !groups.isEmpty()) { - // Convert to Set for lookup convenience - groupsSet.addAll(groups); - - List resourceGroupBeans = groupRolesDAO.getByResource(resource.getId(), resource.getType()); - for (GroupRolesBean resourceGroupBean : resourceGroupBeans) { - if (groupsSet.contains(resourceGroupBean.getGroup_name())) { - if(resourceGroupBean.getRole().isAuthorized(requiredRole)) { - return; - } - } - } - } - - // Consider user role(s) - UserRolesBean userBean = userRolesDAO.getByNameAndResource(userName, resource.getId(), resource.getType()); - if(userBean != null) { - if(userBean.getRole().isAuthorized(requiredRole)) { - return; - } - } - - // Check SYSTEM wide group role - if(groups != null && !groups.isEmpty()) { - List systemGroupBeans = groupRolesDAO.getByResource(Resource.ALL, Resource.Type.SYSTEM); - for(GroupRolesBean group : systemGroupBeans) { - if(groupsSet.contains(group.getGroup_name())) { - if (group.getRole().isAuthorized(requiredRole)) { - return; - } - } - } - } - - // Consider SYSTEM wide role - UserRolesBean systemBean = userRolesDAO.getByNameAndResource(userName, Resource.ALL, Resource.Type.SYSTEM); - if (systemBean != null) { - if(systemBean.getRole().isAuthorized(requiredRole)) { - return; - } - } - - // Otherwise not authorized - throw new TeletaanInternalException(Response.Status.FORBIDDEN, "Not authorized!"); - } - - public void checkAPITokenPermission(TokenRolesBean bean, Resource requiredResource, Role requiredRole) throws Exception { - Resource myResource = new Resource(bean.getResource_id(), bean.getResource_type()); - - if ((myResource.equals(requiredResource) && bean.getRole().isAuthorized(requiredRole))) { - // An exact match - return; - } - - if (myResource.getType() == Resource.Type.SYSTEM && bean.getRole().isAuthorized(requiredRole)) { - // More than enough - return; - } - - // Otherwise, no way - throw new TeletaanInternalException(Response.Status.FORBIDDEN, "Not authorized!"); - } - - @Override - public void authorize(SecurityContext securityContext, Resource resource, Role requiredRole) throws Exception { - UserPrincipal principal = (UserPrincipal) securityContext.getUserPrincipal(); - - // Check if script token - if (principal.getTokenRolesBean() != null) { - checkAPITokenPermission(principal.getTokenRolesBean(), resource, requiredRole); - } - // Check user roles if not a script - else { - checkUserPermission(principal.getName(), resource, principal.getGroups(), requiredRole); - } - } -} diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/ScriptTokenRoleAuthorizer.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/ScriptTokenRoleAuthorizer.java new file mode 100644 index 0000000000..fe356567dd --- /dev/null +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/ScriptTokenRoleAuthorizer.java @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2024 Pinterest, 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.pinterest.teletraan.security; + +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; +import com.pinterest.teletraan.universal.security.AuthZResourceExtractor; +import com.pinterest.teletraan.universal.security.BaseAuthorizer; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; +import com.pinterest.teletraan.universal.security.bean.ScriptTokenPrincipal; +import com.pinterest.teletraan.universal.security.bean.ValueBasedRole; +import javax.annotation.Nullable; +import javax.ws.rs.container.ContainerRequestContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ScriptTokenRoleAuthorizer extends BaseAuthorizer> { + private static final Logger LOG = LoggerFactory.getLogger(ScriptTokenRoleAuthorizer.class); + + public ScriptTokenRoleAuthorizer(AuthZResourceExtractor.Factory authZResourceExtractorFactory) { + super(authZResourceExtractorFactory); + } + + @Override + public boolean authorize( + ScriptTokenPrincipal principal, + String role, + AuthZResource requestedResource, + @Nullable ContainerRequestContext context) { + if (!principal + .getRole() + .isEqualOrSuperior(TeletraanPrincipalRoles.valueOf(role).getRole())) { + LOG.info("Requested role does not match principal role"); + return false; + } + + if (requestedResource.getType().equals(AuthZResource.Type.ENV_STAGE)) { + // Convert to ENV for backward compatibility + requestedResource = + new AuthZResource(requestedResource.getName(), AuthZResource.Type.ENV); + } + + if (requestedResource.equals(principal.getResource()) + || principal.getResource().getType().equals(AuthZResource.Type.SYSTEM)) { + LOG.debug("Authorized"); + return true; + } + + LOG.info("Requested resource does not match principal resource"); + return false; + } +} diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/TeletraanAuthZResourceExtractorFactory.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/TeletraanAuthZResourceExtractorFactory.java new file mode 100644 index 0000000000..698fc9b759 --- /dev/null +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/TeletraanAuthZResourceExtractorFactory.java @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2024 Pinterest, 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.pinterest.teletraan.security; + +import javax.ws.rs.container.ContainerRequestContext; + +import com.pinterest.deployservice.ServiceContext; +import com.pinterest.teletraan.universal.security.AuthZResourceExtractor; +import com.pinterest.teletraan.universal.security.ResourceAuthZInfo; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + +public class TeletraanAuthZResourceExtractorFactory implements AuthZResourceExtractor.Factory { + + private static final AuthZResourceExtractor ENV_PATH_EXTRACTOR = new EnvPathExtractor(); + private static final AuthZResourceExtractor ENV_STAGE_PATH_EXTRACTOR = + new EnvStagePathExtractor(); + private final AuthZResourceExtractor ENV_STAGE_BODY_EXTRACTOR; + + public TeletraanAuthZResourceExtractorFactory(ServiceContext serviceContext) { + ENV_STAGE_BODY_EXTRACTOR = new EnvStageBodyExtractor(serviceContext); + } + + @Override + public AuthZResourceExtractor create(ResourceAuthZInfo authZInfo) { + switch (authZInfo.type()) { + case ENV: + switch (authZInfo.idLocation()) { + case PATH: + return ENV_PATH_EXTRACTOR; + default: + throw new UnsupportedResourceIDLocationException(authZInfo); + } + case ENV_STAGE: + switch (authZInfo.idLocation()) { + case PATH: + return ENV_STAGE_PATH_EXTRACTOR; + case BODY: + return ENV_STAGE_BODY_EXTRACTOR; + default: + throw new UnsupportedResourceIDLocationException(authZInfo); + } + case RATINGS: + return new AuthZResourceExtractor() { + @Override + public AuthZResource extractResource(ContainerRequestContext requestContext) + throws ExtractionException { + return new AuthZResource("rating", AuthZResource.Type.RATINGS); + } + + }; + default: + throw new IllegalArgumentException( + "Unsupported resource type: " + authZInfo.type()); + } + } + + class UnsupportedResourceIDLocationException extends RuntimeException { + public UnsupportedResourceIDLocationException(ResourceAuthZInfo authZInfo) { + super(String.format("Unsupported resource ID location %s for type %s", authZInfo.idLocation(), authZInfo.type())); + } + } +} diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/TeletraanScriptTokenProvider.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/TeletraanScriptTokenProvider.java new file mode 100644 index 0000000000..8a0bd3f9a8 --- /dev/null +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/TeletraanScriptTokenProvider.java @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2024 Pinterest, 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.pinterest.teletraan.security; + +import com.pinterest.deployservice.ServiceContext; +import com.pinterest.deployservice.bean.TokenRolesBean; +import com.pinterest.teletraan.universal.security.ScriptTokenProvider; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; +import com.pinterest.teletraan.universal.security.bean.ScriptTokenPrincipal; +import com.pinterest.teletraan.universal.security.bean.ValueBasedRole; + +import java.util.Optional; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TeletraanScriptTokenProvider implements ScriptTokenProvider { + private static final Logger LOG = LoggerFactory.getLogger(TeletraanScriptTokenProvider.class); + + private ServiceContext context; + + public TeletraanScriptTokenProvider(ServiceContext context) { + this.context = context; + } + + @Override + public Optional> getPrincipal(String token) { + try { + TokenRolesBean tokenRolesBean = context.getTokenRolesDAO().getByToken(token); + + if (tokenRolesBean != null) { + return Optional.of(new ScriptTokenPrincipal( + tokenRolesBean.getScript_name(), tokenRolesBean.getRole().getRole(), + new AuthZResource(tokenRolesBean.getResource_id(), tokenRolesBean.getResource_type()))); + } + } catch (Exception e) { + LOG.error("failed to get Script token principal", e); + } + return Optional.empty(); + } +} diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/TokenAuthFilter.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/TokenAuthFilter.java deleted file mode 100644 index 97c1ce6315..0000000000 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/TokenAuthFilter.java +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright 2016 Pinterest, 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.pinterest.teletraan.security; - -import com.pinterest.deployservice.common.DeployInternalException; -import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.deployservice.exception.TeletaanInternalException; - -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; - -import javax.annotation.Priority; -import javax.ws.rs.Priorities; -import javax.ws.rs.container.ContainerRequestContext; -import javax.ws.rs.container.ContainerRequestFilter; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.SecurityContext; -import javax.ws.rs.ext.Provider; -import javax.ws.rs.core.UriInfo; - -@Provider -@Priority(Priorities.AUTHENTICATION) -public class TokenAuthFilter implements ContainerRequestFilter { - - private static final String AUTHENTICATION_HEADER = "Authorization"; - private static final String TELETRAAN_TOKEN_SCHEME = "token"; - private static final Logger LOG = LoggerFactory.getLogger(TokenAuthFilter.class); - - private UserDataHelper userDataHelper; - - public TokenAuthFilter(String userDataUrl, String groupDataUrl, String userNameKey, Boolean extractUserNameFromEmail, String tokenCacheSpec, TeletraanServiceContext context) throws Exception { - userDataHelper = new UserDataHelper(userDataUrl, groupDataUrl, userNameKey, extractUserNameFromEmail, tokenCacheSpec, context); - } - - @Override - public void filter(ContainerRequestContext context) throws IOException { - if(!context.getMethod().equals("OPTIONS")) { - SecurityContext securityContext; - try { - securityContext = authenticate(context); - if ( securityContext != null ) { - LOG.info(String.format("{\"requestMethod\": \"%s\", \"requestUri\": \"%s\", \"userName\": \"%s\"}", context.getMethod(), context.getUriInfo().getRequestUri(), securityContext.getUserPrincipal().getName())); - } - } catch (Exception e) { - LOG.info("Authentication failed. Reason: " + e.getMessage()); - throw new TeletaanInternalException(Response.Status.UNAUTHORIZED, - "Failed to authenticate user. " + e.getMessage()); - } - context.setSecurityContext(securityContext); - } - } - - private SecurityContext authenticate(ContainerRequestContext context) throws Exception { - String authCredentials = context.getHeaderString(AUTHENTICATION_HEADER); - UriInfo uriInfo = context.getUriInfo(); - if (StringUtils.isEmpty(authCredentials)) { - if (!uriInfo.getAbsolutePath().equals("healthcheck") && - !uriInfo.getAbsolutePath().equals("/healthcheck") && - !uriInfo.getPath().equals("healthcheck") && - !uriInfo.getPath().equals("/healthcheck")) { - throw new DeployInternalException("Can not find HTTP header: Authorization!"); - } - return null; - } - - String[] schemeAndToken = authCredentials.trim().split(" "); - String scheme = schemeAndToken[0].trim(); - String token = schemeAndToken[1].trim(); - - if (scheme.equalsIgnoreCase(TELETRAAN_TOKEN_SCHEME)) { - return userDataHelper.getUserSecurityContext(token); - } - - throw new DeployInternalException("Authorization scheme " + scheme + " is not supported!"); - } -} diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/UserDataHelper.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/UserDataHelper.java deleted file mode 100644 index 2db5e3c57e..0000000000 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/UserDataHelper.java +++ /dev/null @@ -1,134 +0,0 @@ -/** - * Copyright 2016 Pinterest, 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.pinterest.teletraan.security; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableMap; -import com.google.gson.*; -import com.pinterest.deployservice.bean.TokenRolesBean; -import com.pinterest.deployservice.common.HTTPClient; -import com.pinterest.teletraan.TeletraanServiceContext; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; - -public class UserDataHelper { - private String userDataUrl; - private String groupDataUrl; - private String[] userNameKeys; - private Boolean extractUserNameFromEmail; - private LoadingCache tokenCache; - private TeletraanServiceContext context; - private static final Logger LOG = LoggerFactory.getLogger(UserDataHelper.class); - - public UserDataHelper(String userDataUrl, String groupDataUrl, String userNameKey, Boolean extractUserNameFromEmail, String tokenCacheSpec, TeletraanServiceContext context) { - this.userDataUrl = userDataUrl; - this.groupDataUrl = groupDataUrl; - this.context = context; - this.extractUserNameFromEmail = extractUserNameFromEmail; - if (!StringUtils.isEmpty(tokenCacheSpec)) { - tokenCache = CacheBuilder.from(tokenCacheSpec) - .build(new CacheLoader() { - @Override - public UserSecurityContext load(String token) throws Exception { - return loadOauthUserData(token); - } - }); - } - - // prepare username keys - if (StringUtils.isEmpty(userNameKey)) { - userNameKeys = null; - } else { - userNameKeys = userNameKey.split("\\s+"); - } - } - - public List getUserGroups(String token) throws Exception { - if (StringUtils.isEmpty(groupDataUrl)) { - return Collections.emptyList(); - } - - // Get user groups through auth server with user oauth token - HTTPClient client = new HTTPClient(); - HashMap params = new HashMap<>(); - params.put("access_token", token); - String jsonResponse = client.get(groupDataUrl, null, params, null, 3); - - // Parse response - Gson gson = new Gson(); - JsonParser parser = new JsonParser(); - JsonElement element = parser.parse(jsonResponse); - - if (element.getAsJsonObject().has("groups")) { - JsonArray jsonArray = element.getAsJsonObject().getAsJsonArray("groups"); - String[] groups = gson.fromJson(jsonArray, String[].class); - LOG.info("Retrieved groups " + Arrays.asList(groups).toString() + " from token."); - return Arrays.asList(groups); - } - - return null; - } - - public String getUsername(String token) throws Exception { - HTTPClient httpClient = new HTTPClient(); - Map params = ImmutableMap.of("access_token", token); - String jsonPayload = httpClient.get(userDataUrl, null, params, null, 3); - JsonElement e = new JsonParser().parse(jsonPayload); - String userName; - if (userNameKeys != null && userNameKeys.length > 0) { - JsonObject jsonObject = e.getAsJsonObject(); - int i = 0; - for (; i < userNameKeys.length - 1; i++) { - jsonObject = jsonObject.getAsJsonObject(userNameKeys[i]); - } - userName = jsonObject.get(userNameKeys[i]).getAsString(); - } else { - userName = e.getAsString(); - } - if (extractUserNameFromEmail != null && extractUserNameFromEmail) { - userName = userName.split("@")[0]; - } - LOG.info("Retrieved username " + userName + " from token."); - return userName; - } - - public UserSecurityContext loadOauthUserData(String token) throws Exception { - TokenRolesBean tokenRolesBean = context.getTokenRolesDAO().getByToken(token); - - // Script token - if (tokenRolesBean != null) { - return new UserSecurityContext(tokenRolesBean.getScript_name(), tokenRolesBean, null); - } - - // User token - String username = getUsername(token); - List groups = getUserGroups(token); - return new UserSecurityContext(username, null, groups); - } - - public UserSecurityContext getUserSecurityContext(String token) throws Exception { - if (tokenCache == null) { - return loadOauthUserData(token); - } else { - return tokenCache.get(token); - } - } -} diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/UserPrincipal.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/UserPrincipal.java deleted file mode 100644 index 1cc140307d..0000000000 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/UserPrincipal.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright 2016 Pinterest, 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.pinterest.teletraan.security; - -import com.pinterest.deployservice.bean.TokenRolesBean; - -import java.security.Principal; -import java.util.List; - -public class UserPrincipal implements Principal { - private String user; - private TokenRolesBean tokenRolesBean; - private List groups; - - public UserPrincipal(String user, TokenRolesBean tokenRolesBean, List groups) { - this.user = user; - this.tokenRolesBean = tokenRolesBean; - this.groups = groups; - } - - @Override - public String getName() { - return user; - } - - public String getUser() { - return user; - } - - public List getGroups() { - return groups; - } - - public TokenRolesBean getTokenRolesBean() { - return tokenRolesBean; - } -} diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/UserResourceKey.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/UserResourceKey.java deleted file mode 100644 index 8d8fa871bd..0000000000 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/UserResourceKey.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright 2016 Pinterest, 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.pinterest.teletraan.security; - -import com.pinterest.deployservice.bean.Resource; - -public class UserResourceKey { - private String userName; - private Resource resource; - - public UserResourceKey(String userName, Resource resource) { - this.userName = userName; - this.resource = resource; - } - - public String getUserName() { - return userName; - } - - public Resource getResource() { - return resource; - } -} diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/UserRoleAuthorizer.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/UserRoleAuthorizer.java new file mode 100644 index 0000000000..d0d52a4042 --- /dev/null +++ b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/UserRoleAuthorizer.java @@ -0,0 +1,133 @@ +/** + * Copyright (c) 2024 Pinterest, 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.pinterest.teletraan.security; + +import com.pinterest.deployservice.ServiceContext; +import com.pinterest.deployservice.bean.EnvironBean; +import com.pinterest.deployservice.bean.GroupRolesBean; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; +import com.pinterest.deployservice.bean.UserRolesBean; +import com.pinterest.deployservice.dao.EnvironDAO; +import com.pinterest.deployservice.dao.GroupRolesDAO; +import com.pinterest.deployservice.dao.UserRolesDAO; +import com.pinterest.teletraan.universal.security.AuthZResourceExtractor; +import com.pinterest.teletraan.universal.security.BaseAuthorizer; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; +import com.pinterest.teletraan.universal.security.bean.UserPrincipal; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.annotation.Nullable; +import javax.ws.rs.container.ContainerRequestContext; +import org.apache.commons.collections.CollectionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Deprecated +public class UserRoleAuthorizer extends BaseAuthorizer { + private static final Logger LOG = LoggerFactory.getLogger(UserRoleAuthorizer.class); + private final UserRolesDAO userRolesDAO; + private final GroupRolesDAO groupRolesDAO; + private final EnvironDAO environDAO; + + public UserRoleAuthorizer( + ServiceContext context, AuthZResourceExtractor.Factory authZResourceExtractorFactory) { + super(authZResourceExtractorFactory); + userRolesDAO = context.getUserRolesDAO(); + groupRolesDAO = context.getGroupRolesDAO(); + environDAO = context.getEnvironDAO(); + } + + @Override + public boolean authorize( + UserPrincipal principal, + String role, + AuthZResource requestedResource, + @Nullable ContainerRequestContext context) { + try { + TeletraanPrincipalRoles requiredRole = TeletraanPrincipalRoles.valueOf(role); + AuthZResource convertedRequestedResource = requestedResource; + if (AuthZResource.Type.ENV_STAGE.equals(convertedRequestedResource.getType())) { + // Convert to ENV for backward compatibility + convertedRequestedResource = new AuthZResource(convertedRequestedResource.getName(), + AuthZResource.Type.ENV); + } + + // Consider group role(s) + Set groupsSet = new HashSet<>(); + if (principal.getGroups() != null && !principal.getGroups().isEmpty()) { + // Convert to Set for lookup convenience + groupsSet.addAll(principal.getGroups()); + + List resourceGroupBeans = groupRolesDAO.getByResource( + convertedRequestedResource.getName(), convertedRequestedResource.getType()); + for (GroupRolesBean resourceGroupBean : resourceGroupBeans) { + if (groupsSet.contains(resourceGroupBean.getGroup_name()) + && resourceGroupBean.getRole().isEqualOrSuperior(requiredRole)) { + return true; + } + } + } + + // Consider user role(s) + UserRolesBean userBean = userRolesDAO.getByNameAndResource( + principal.getName(), + convertedRequestedResource.getName(), + convertedRequestedResource.getType()); + if (userBean != null && userBean.getRole().isEqualOrSuperior(requiredRole)) { + return true; + } + + // Check SYSTEM wide group role + if (principal.getGroups() != null && !principal.getGroups().isEmpty()) { + List systemGroupBeans = groupRolesDAO.getByResource(AuthZResource.ALL, + AuthZResource.Type.SYSTEM); + for (GroupRolesBean group : systemGroupBeans) { + if (groupsSet.contains(group.getGroup_name()) && group.getRole().isEqualOrSuperior(requiredRole)) { + return true; + } + } + } + + // Consider SYSTEM wide role + UserRolesBean systemBean = userRolesDAO.getByNameAndResource( + principal.getName(), AuthZResource.ALL, AuthZResource.Type.SYSTEM); + if (systemBean != null && systemBean.getRole().isEqualOrSuperior(requiredRole)) { + return true; + } + + // Special case for creating a new environment + if (AuthZResource.Type.ENV.equals(requestedResource.getType()) + && requiredRole.equals(TeletraanPrincipalRoles.WRITE)) { + String envName = convertedRequestedResource.getName().split("/")[0]; + List environBeans = environDAO.getByName(envName); + if (CollectionUtils.isEmpty(environBeans)) { + return true; + } + } + + if (AuthZResource.Type.RATINGS.equals(convertedRequestedResource.getType()) + && TeletraanPrincipalRoles.WRITE.equals(requiredRole)) { + return true; + } + + return false; + } catch (Exception ex) { + LOG.error("Authorization failed", ex); + return false; + } + } +} diff --git a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/UserSecurityContext.java b/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/UserSecurityContext.java deleted file mode 100644 index c449166682..0000000000 --- a/deploy-service/teletraanservice/src/main/java/com/pinterest/teletraan/security/UserSecurityContext.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright 2016 Pinterest, 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.pinterest.teletraan.security; - -import com.pinterest.deployservice.bean.TokenRolesBean; - -import javax.ws.rs.core.SecurityContext; -import java.security.Principal; -import java.util.List; - -public class UserSecurityContext implements SecurityContext { - private UserPrincipal userPrincipal; - - public UserSecurityContext(String user, TokenRolesBean tokenRolesBean, List ldapGroups) { - userPrincipal = new UserPrincipal(user, tokenRolesBean, ldapGroups); - } - - @Override - public Principal getUserPrincipal() { - return userPrincipal; - } - - @Override - public boolean isUserInRole(String requiredRole) { - return false; - } - - @Override - public boolean isSecure() { - return false; - } - - @Override - public String getAuthenticationScheme() { - return null; - } -} diff --git a/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/fixture/EnvironBeanFixture.java b/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/fixture/EnvironBeanFixture.java new file mode 100644 index 0000000000..863bfa7489 --- /dev/null +++ b/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/fixture/EnvironBeanFixture.java @@ -0,0 +1,41 @@ +package com.pinterest.teletraan.fixture; + +import java.util.Random; +import java.util.UUID; + +import com.pinterest.deployservice.bean.AcceptanceType; +import com.pinterest.deployservice.bean.EnvironBean; +import com.pinterest.deployservice.bean.EnvironState; +import com.pinterest.deployservice.bean.OverridePolicy; + +public class EnvironBeanFixture { + private static final Random RANDOM = new Random(System.currentTimeMillis()); + + public static EnvironBean createRandomEnvironBean() { + EnvironBean environBean = new EnvironBean(); + environBean.setEnv_name(UUID.randomUUID().toString()); + environBean.setStage_name(UUID.randomUUID().toString()); + environBean.setEnv_id(UUID.randomUUID().toString()); + environBean.setDeploy_id(UUID.randomUUID().toString()); + environBean.setState(EnvironState.NORMAL); + environBean.setSuccess_th(10000); + environBean.setDescription("description"); + environBean.setAdv_config_id("config_id_1"); + environBean.setSc_config_id("envvar_id_1"); + environBean.setLast_operator("bar"); + environBean.setLast_update(System.currentTimeMillis()); + environBean.setAccept_type(AcceptanceType.AUTO); + environBean.setNotify_authors(false); + environBean.setWatch_recipients("watcher"); + environBean.setMax_deploy_num(5100); + environBean.setMax_deploy_day(366); + environBean.setIs_docker(false); + environBean.setMax_parallel_pct(0); + environBean.setState(EnvironState.NORMAL); + environBean.setMax_parallel_rp(1); + environBean.setOverride_policy(OverridePolicy.OVERRIDE); + environBean.setAllow_private_build(false); + environBean.setEnsure_trusted_build(false); + return environBean; + } +} diff --git a/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/resource/EnvAlertsTest.java b/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/resource/EnvAlertsTest.java index 33b4d61298..f6cd0c4347 100644 --- a/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/resource/EnvAlertsTest.java +++ b/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/resource/EnvAlertsTest.java @@ -16,7 +16,6 @@ import com.pinterest.deployservice.bean.EnvironBean; import com.pinterest.deployservice.bean.EnvironState; import com.pinterest.deployservice.bean.TagBean; -import com.pinterest.deployservice.bean.TokenRolesBean; import com.pinterest.deployservice.buildtags.BuildTagsManager; import com.pinterest.deployservice.common.Constants; import com.pinterest.deployservice.dao.BuildDAO; @@ -26,8 +25,7 @@ import com.pinterest.deployservice.handler.DeployHandlerInterface; import com.pinterest.deployservice.handler.TagHandler; import com.pinterest.teletraan.TeletraanServiceContext; -import com.pinterest.teletraan.security.Authorizer; -import com.pinterest.teletraan.security.UserPrincipal; +import com.pinterest.teletraan.universal.security.bean.UserPrincipal; import org.joda.time.DateTime; import org.junit.Assert; @@ -43,7 +41,6 @@ public class EnvAlertsTest { TeletraanServiceContext context; - Authorizer authorizer; DeployBean recent = new DeployBean(); DeployBean lastKnownGoodDeploy = new DeployBean(); EnvironBean environBean = new EnvironBean(); @@ -66,7 +63,6 @@ public void setUp() throws Exception { environDAO = mock(EnvironDAO.class); deployDAO = mock(DeployDAO.class); tagDAO = mock(TagDAO.class); - authorizer = mock(Authorizer.class); buildTagsManager = mock(BuildTagsManager.class); alertContextBuilder = mock(AlertContextBuilder.class); deployHandler = mock(DeployHandlerInterface.class); @@ -75,7 +71,6 @@ public void setUp() throws Exception { context.setBuildDAO(buildDAO); context.setEnvironDAO(environDAO); context.setDeployDAO(deployDAO); - context.setAuthorizer(authorizer); context.setExternalAlertsFactory(new PinterestExternalAlertFactory()); buildBean.setBuild_id("0000001"); buildBean.setBuild_name("BuildOne"); @@ -98,7 +93,7 @@ public void setUp() throws Exception { when(deployDAO.getById("recentdeploy")).thenReturn(recent); when(deployDAO.getById("lastGoodDeploy")).thenReturn(recent); sc = mock(SecurityContext.class); - when(sc.getUserPrincipal()).thenReturn(new UserPrincipal(Constants.AUTO_PROMOTER_NAME, new TokenRolesBean(),new ArrayList())); + when(sc.getUserPrincipal()).thenReturn(new UserPrincipal(Constants.AUTO_PROMOTER_NAME, new ArrayList())); when(buildDAO.getById(recent.getBuild_id())).thenReturn(buildBean); alertContext = new AlertContext(); alertContext.setTagHandler(mock(TagHandler.class)); diff --git a/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/BasePathExtractorTest.java b/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/BasePathExtractorTest.java new file mode 100644 index 0000000000..b28069fc9d --- /dev/null +++ b/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/BasePathExtractorTest.java @@ -0,0 +1,27 @@ +package com.pinterest.teletraan.security; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.core.MultivaluedHashMap; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.UriInfo; + +import org.junit.jupiter.api.BeforeEach; + +abstract class BasePathExtractorTest { + protected ContainerRequestContext context; + protected MultivaluedMap pathParameters; + + @BeforeEach + void setUp() { + UriInfo uriInfo = mock(UriInfo.class); + + context = mock(ContainerRequestContext.class); + pathParameters = new MultivaluedHashMap<>(); + + when(context.getUriInfo()).thenReturn(uriInfo); + when(uriInfo.getPathParameters()).thenReturn(pathParameters); + } +} diff --git a/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/EnvPathExtractorTest.java b/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/EnvPathExtractorTest.java new file mode 100644 index 0000000000..7a58a1708a --- /dev/null +++ b/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/EnvPathExtractorTest.java @@ -0,0 +1,55 @@ +package com.pinterest.teletraan.security; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.pinterest.teletraan.universal.security.AuthZResourceExtractor.ExtractionException; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + +class EnvPathExtractorTest extends BasePathExtractorTest { + private EnvPathExtractor sut; + + @BeforeEach + void setUp() { + super.setUp(); + sut = new EnvPathExtractor(); + } + + @Test + void testExtractResource_noPathParams_exception() { + assertThrows(ExtractionException.class, () -> sut.extractResource(context)); + } + + @Test + void testExtractResource_0EnvName() { + pathParameters.add("nonEnvName", "testEnv"); + + assertThrows(ExtractionException.class, () -> sut.extractResource(context)); + } + + @Test + void testExtractResource_1EnvName() throws ExtractionException { + pathParameters.add("envName", "testEnv"); + + AuthZResource resource = sut.extractResource(context); + assertNotNull(resource); + assertEquals("testEnv", resource.getName()); + assertEquals(AuthZResource.Type.ENV, resource.getType()); + } + + @Test + void testExtractResource_2EnvNames() throws ExtractionException + { + pathParameters.add("envName", "testEnv"); + pathParameters.add("envName", "testEnv2"); + + AuthZResource resource = sut.extractResource(context); + assertNotNull(resource); + assertEquals("testEnv", resource.getName()); + assertEquals(AuthZResource.Type.ENV, resource.getType()); + } +} diff --git a/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/EnvStageBodyExtractorTest.java b/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/EnvStageBodyExtractorTest.java new file mode 100644 index 0000000000..b5a97cdc3f --- /dev/null +++ b/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/EnvStageBodyExtractorTest.java @@ -0,0 +1,163 @@ +package com.pinterest.teletraan.security; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +import javax.ws.rs.container.ContainerRequestContext; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.pinterest.deployservice.ServiceContext; +import com.pinterest.deployservice.bean.AgentBean; +import com.pinterest.deployservice.bean.DeployBean; +import com.pinterest.deployservice.bean.EnvironBean; +import com.pinterest.deployservice.bean.HotfixBean; +import com.pinterest.deployservice.dao.EnvironDAO; +import com.pinterest.teletraan.fixture.EnvironBeanFixture; +import com.pinterest.teletraan.security.EnvStageBodyExtractor.BeanClassExtractionException; +import com.pinterest.teletraan.universal.security.AuthZResourceExtractor.ExtractionException; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + +class EnvStageBodyExtractorTest { + + private ContainerRequestContext context; + private EnvStageBodyExtractor sut; + private EnvironDAO environDAO; + private InputStream inputStream; + private ObjectMapper objectMapper = new ObjectMapper(); + private static final Class[] BEAN_CLASSES = { EnvironBean.class, HotfixBean.class, DeployBean.class, AgentBean.class }; + + @BeforeEach + void setUp() { + environDAO = mock(EnvironDAO.class); + context = mock(ContainerRequestContext.class); + + ServiceContext serviceContext = new ServiceContext(); + serviceContext.setEnvironDAO(environDAO); + sut = new EnvStageBodyExtractor(serviceContext); + } + + @Test + void testExtractResource_nothing_exception() throws Exception { + inputStream = mock(InputStream.class); + when(context.getEntityStream()).thenReturn(inputStream); + + assertThrows(ExtractionException.class, () -> sut.extractResource(context)); + } + + @ParameterizedTest + @MethodSource("getSupportedClassed") + void testExtractResource_specificBeanClass_emptyStream(Class beanClass) throws Exception { + inputStream = mock(InputStream.class); + when(context.getEntityStream()).thenReturn(inputStream); + + assertThrows(BeanClassExtractionException.class, () -> sut.extractResource(context, beanClass)); + } + + @ParameterizedTest + @MethodSource("getSupportedClassed") + void testExtractResource_environBean_success(Class beanClass) throws Exception { + EnvironBean envBean = EnvironBeanFixture.createRandomEnvironBean(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + objectMapper.writeValue(out, envBean); + inputStream = new ByteArrayInputStream(out.toByteArray()); + + when(context.getEntityStream()).thenReturn(inputStream); + + if (beanClass.equals(EnvironBean.class)) { + AuthZResource resource = sut.extractResource(context, EnvironBean.class); + assertTrue(resource.getName().contains(envBean.getEnv_name())); + assertTrue(resource.getName().contains(envBean.getStage_name())); + assertEquals(AuthZResource.Type.ENV_STAGE, resource.getType()); + } else { + assertThrows(BeanClassExtractionException.class, () -> sut.extractResource(context, beanClass)); + } + } + + @ParameterizedTest + @MethodSource("getSupportedClassed") + void testExtractResource_hotFixBean_success(Class beanClass) throws Exception { + HotfixBean hotfixBean = new HotfixBean(); + hotfixBean.setEnv_name("env_name"); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + objectMapper.writeValue(out, hotfixBean); + inputStream = new ByteArrayInputStream(out.toByteArray()); + + when(context.getEntityStream()).thenReturn(inputStream); + + if (beanClass.equals(HotfixBean.class)) { + + AuthZResource resource = sut.extractResource(context, HotfixBean.class); + assertTrue(resource.getName().contains(hotfixBean.getEnv_name())); + assertEquals(AuthZResource.Type.ENV_STAGE, resource.getType()); + } else { + assertThrows(BeanClassExtractionException.class, () -> sut.extractResource(context, beanClass)); + } + } + + @ParameterizedTest + @MethodSource("getSupportedClassed") + void testExtractResource_deployFixBean_success(Class beanClass) throws Exception { + EnvironBean envBean = EnvironBeanFixture.createRandomEnvironBean(); + DeployBean deployBean = new DeployBean(); + String envId = "env_id"; + deployBean.setEnv_id(envId); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + objectMapper.writeValue(out, deployBean); + inputStream = new ByteArrayInputStream(out.toByteArray()); + + when(context.getEntityStream()).thenReturn(inputStream); + when(environDAO.getById(envId)).thenReturn(envBean); + + if (beanClass.equals(DeployBean.class)) { + AuthZResource resource = sut.extractResource(context, DeployBean.class); + assertTrue(resource.getName().contains(envBean.getEnv_name())); + assertTrue(resource.getName().contains(envBean.getStage_name())); + assertEquals(AuthZResource.Type.ENV_STAGE, resource.getType()); + } else { + assertThrows(BeanClassExtractionException.class, () -> sut.extractResource(context, beanClass)); + } + } + + @ParameterizedTest + @MethodSource("getSupportedClassed") + void testExtractResource_agentBean_success(Class beanClass) throws Exception { + EnvironBean envBean = EnvironBeanFixture.createRandomEnvironBean(); + AgentBean agentBean = new AgentBean(); + String envId = "env_id"; + agentBean.setEnv_id(envId); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + objectMapper.writeValue(out, agentBean); + inputStream = new ByteArrayInputStream(out.toByteArray()); + + when(context.getEntityStream()).thenReturn(inputStream); + when(environDAO.getById(envId)).thenReturn(envBean); + + if (beanClass.equals(AgentBean.class)) { + AuthZResource resource = sut.extractResource(context, AgentBean.class); + assertTrue(resource.getName().contains(envBean.getEnv_name())); + assertTrue(resource.getName().contains(envBean.getStage_name())); + assertEquals(AuthZResource.Type.ENV_STAGE, resource.getType()); + } else { + assertThrows(BeanClassExtractionException.class, () -> sut.extractResource(context, beanClass)); + } + } + + static Class[] getSupportedClassed() { + return BEAN_CLASSES; + } + +} diff --git a/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/EnvStagePathExtractorTest.java b/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/EnvStagePathExtractorTest.java new file mode 100644 index 0000000000..1c94860071 --- /dev/null +++ b/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/EnvStagePathExtractorTest.java @@ -0,0 +1,78 @@ +package com.pinterest.teletraan.security; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.pinterest.teletraan.universal.security.AuthZResourceExtractor.ExtractionException; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; + +class EnvStagePathExtractorTest extends BasePathExtractorTest { + private EnvStagePathExtractor sut; + private static final String ENV_NAME_KEY = "envName"; + private static final String STAGE_NAME_KEY = "stageName"; + + @BeforeEach + void setUp() { + super.setUp(); + sut = new EnvStagePathExtractor(); + } + + @Test + void testExtractResource_noPathParams_exception() { + assertThrows(ExtractionException.class, () -> sut.extractResource(context)); + } + + @Test + void testExtractResource_0EnvName() { + pathParameters.add("nonEnvName", "testEnv"); + + assertThrows(ExtractionException.class, () -> sut.extractResource(context)); + } + + @Test + void testExtractResource_onlyStageName() { + pathParameters.add(STAGE_NAME_KEY, "testEnv"); + + assertThrows(ExtractionException.class, () -> sut.extractResource(context)); + } + + @Test + void testExtractResource_1EnvName() throws ExtractionException { + pathParameters.add(ENV_NAME_KEY, "testEnv"); + + AuthZResource resource = sut.extractResource(context); + assertNotNull(resource); + assertTrue(resource.getName().contains("testEnv")); + assertEquals(AuthZResource.Type.ENV_STAGE, resource.getType()); + } + + @Test + void testExtractResource_1EnvName1StageName() throws ExtractionException { + pathParameters.add(ENV_NAME_KEY, "testEnv"); + pathParameters.add(STAGE_NAME_KEY, "testStage"); + + AuthZResource resource = sut.extractResource(context); + assertNotNull(resource); + assertTrue(resource.getName().contains("testEnv")); + assertTrue(resource.getName().contains("testStage")); + assertEquals(AuthZResource.Type.ENV_STAGE, resource.getType()); + } + + @Test + void testExtractResource_2EnvNames1StageName() throws ExtractionException { + pathParameters.add(ENV_NAME_KEY, "testEnv"); + pathParameters.add(ENV_NAME_KEY, "testEnv2"); + pathParameters.add(STAGE_NAME_KEY, "testStage"); + + AuthZResource resource = sut.extractResource(context); + assertNotNull(resource); + assertTrue(resource.getName().contains("testEnv")); + assertTrue(resource.getName().contains("testStage")); + assertEquals(AuthZResource.Type.ENV_STAGE, resource.getType()); + } +} diff --git a/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/ScriptTokenAuthorizerTest.java b/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/ScriptTokenAuthorizerTest.java deleted file mode 100644 index 01b5adfbde..0000000000 --- a/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/ScriptTokenAuthorizerTest.java +++ /dev/null @@ -1,156 +0,0 @@ -/** - * Copyright 2016 Pinterest, 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.pinterest.teletraan.security; - -import com.pinterest.deployservice.ServiceContext; -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; -import com.pinterest.deployservice.bean.TokenRolesBean; -import com.pinterest.deployservice.exception.TeletaanInternalException; -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.assertFalse; - -public class ScriptTokenAuthorizerTest { - private ServiceContext context; - private RoleAuthorizer authorizer; - - private TokenRolesBean sysAdmin; - private TokenRolesBean sysOperator; - private TokenRolesBean sysReader; - - private TokenRolesBean envAdmin; - private TokenRolesBean envOperator; - private TokenRolesBean envReader; - - private Resource env1; - private Resource envX; - - @Before - public void setUp() throws Exception { - context = new ServiceContext(); - context.setUserRolesDAO(null); - authorizer = new RoleAuthorizer(context, null); - - sysAdmin = new TokenRolesBean(); - sysAdmin.setResource_id(Resource.ALL); - sysAdmin.setResource_type(Resource.Type.SYSTEM); - sysAdmin.setRole(Role.ADMIN); - - sysOperator = new TokenRolesBean(); - sysOperator.setResource_id(Resource.ALL); - sysOperator.setResource_type(Resource.Type.SYSTEM); - sysOperator.setRole(Role.OPERATOR); - - sysReader = new TokenRolesBean(); - sysReader.setResource_id(Resource.ALL); - sysReader.setResource_type(Resource.Type.SYSTEM); - sysReader.setRole(Role.READER); - - envAdmin = new TokenRolesBean(); - envAdmin.setResource_id("envX"); - envAdmin.setResource_type(Resource.Type.ENV); - envAdmin.setRole(Role.ADMIN); - - envOperator = new TokenRolesBean(); - envOperator.setResource_id("envX"); - envOperator.setResource_type(Resource.Type.ENV); - envOperator.setRole(Role.OPERATOR); - - envReader = new TokenRolesBean(); - envReader.setResource_id("envX"); - envReader.setResource_type(Resource.Type.ENV); - envReader.setRole(Role.READER); - - env1 = new Resource("env1", Resource.Type.ENV); - envX = new Resource("envX", Resource.Type.ENV); - } - - private void checkPositive(TokenRolesBean bean, Resource resource, Role role) throws Exception { - authorizer.checkAPITokenPermission(bean, resource, role); - } - - private void checkNegative(TokenRolesBean bean, Resource resource, Role role) throws Exception { - try { - authorizer.checkAPITokenPermission(bean, resource, role); - } catch (TeletaanInternalException e) { - // expected - return; - } - assertFalse("Expecting exception", true); - } - - @Test - public void testSysEnv() throws Exception { - checkPositive(sysAdmin, env1, Role.OPERATOR); - checkPositive(sysAdmin, env1, Role.ADMIN); - - checkPositive(sysOperator, env1, Role.OPERATOR); - checkNegative(sysOperator, env1, Role.ADMIN); - - checkNegative(sysReader, env1, Role.OPERATOR); - checkNegative(sysReader, env1, Role.ADMIN); - } - - @Test - public void testSysSys() throws Exception { - checkPositive(sysAdmin, Resource.SYSTEM_RESOURCE, Role.OPERATOR); - checkPositive(sysAdmin, Resource.SYSTEM_RESOURCE, Role.ADMIN); - - checkPositive(sysOperator, Resource.SYSTEM_RESOURCE, Role.OPERATOR); - checkNegative(sysOperator, Resource.SYSTEM_RESOURCE, Role.ADMIN); - - checkNegative(sysReader, Resource.SYSTEM_RESOURCE, Role.OPERATOR); - checkNegative(sysReader, Resource.SYSTEM_RESOURCE, Role.ADMIN); - } - - @Test - public void testEnvSys() throws Exception { - checkNegative(envAdmin, Resource.SYSTEM_RESOURCE, Role.OPERATOR); - checkNegative(envAdmin, Resource.SYSTEM_RESOURCE, Role.ADMIN); - - checkNegative(envOperator, Resource.SYSTEM_RESOURCE, Role.OPERATOR); - checkNegative(envOperator, Resource.SYSTEM_RESOURCE, Role.ADMIN); - - checkNegative(envReader, Resource.SYSTEM_RESOURCE, Role.OPERATOR); - checkNegative(envReader, Resource.SYSTEM_RESOURCE, Role.ADMIN); - } - - @Test - public void testEnvXEnv1() throws Exception { - checkNegative(envAdmin, env1, Role.OPERATOR); - checkNegative(envAdmin, env1, Role.ADMIN); - - checkNegative(envOperator, env1, Role.OPERATOR); - checkNegative(envOperator, env1, Role.ADMIN); - - checkNegative(envReader, env1, Role.OPERATOR); - checkNegative(envReader, env1, Role.ADMIN); - } - - @Test - public void testEnvXEnvX() throws Exception { - checkPositive(envAdmin, envX, Role.OPERATOR); - checkPositive(envAdmin, envX, Role.ADMIN); - - checkPositive(envOperator, envX, Role.OPERATOR); - checkNegative(envOperator, envX, Role.ADMIN); - - checkNegative(envReader, envX, Role.OPERATOR); - checkNegative(envReader, envX, Role.ADMIN); - } -} diff --git a/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/ScriptTokenRoleAuthorizerTest.java b/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/ScriptTokenRoleAuthorizerTest.java new file mode 100644 index 0000000000..a38a5d1aaf --- /dev/null +++ b/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/ScriptTokenRoleAuthorizerTest.java @@ -0,0 +1,206 @@ +/** + * Copyright (c) 2016-2024 Pinterest, 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.pinterest.teletraan.security; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.pinterest.deployservice.ServiceContext; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; +import com.pinterest.deployservice.bean.TokenRolesBean; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; +import com.pinterest.teletraan.universal.security.bean.ScriptTokenPrincipal; +import com.pinterest.teletraan.universal.security.bean.ValueBasedRole; +import org.junit.Before; +import org.junit.Test; + +public class ScriptTokenRoleAuthorizerTest { + private ServiceContext context; + private ScriptTokenRoleAuthorizer authorizer; + + private TokenRolesBean sysAdmin; + private TokenRolesBean sysOperator; + private TokenRolesBean sysReader; + + private TokenRolesBean envAdmin; + private TokenRolesBean envOperator; + private TokenRolesBean envReader; + + private AuthZResource env1; + private AuthZResource envX; + private AuthZResource envStage; + private AuthZResource envXStage; + + @Before + public void setUp() throws Exception { + context = new ServiceContext(); + context.setUserRolesDAO(null); + authorizer = new ScriptTokenRoleAuthorizer(null); + + sysAdmin = new TokenRolesBean(); + sysAdmin.setResource_id(AuthZResource.ALL); + sysAdmin.setResource_type(AuthZResource.Type.SYSTEM); + sysAdmin.setRole(TeletraanPrincipalRoles.ADMIN); + + sysOperator = new TokenRolesBean(); + sysOperator.setResource_id(AuthZResource.ALL); + sysOperator.setResource_type(AuthZResource.Type.SYSTEM); + sysOperator.setRole(TeletraanPrincipalRoles.OPERATOR); + + sysReader = new TokenRolesBean(); + sysReader.setResource_id(AuthZResource.ALL); + sysReader.setResource_type(AuthZResource.Type.SYSTEM); + sysReader.setRole(TeletraanPrincipalRoles.READER); + + envAdmin = new TokenRolesBean(); + envAdmin.setResource_id("envX"); + envAdmin.setResource_type(AuthZResource.Type.ENV); + envAdmin.setRole(TeletraanPrincipalRoles.ADMIN); + + envOperator = new TokenRolesBean(); + envOperator.setResource_id("envX"); + envOperator.setResource_type(AuthZResource.Type.ENV); + envOperator.setRole(TeletraanPrincipalRoles.OPERATOR); + + envReader = new TokenRolesBean(); + envReader.setResource_id("envX"); + envReader.setResource_type(AuthZResource.Type.ENV); + envReader.setRole(TeletraanPrincipalRoles.READER); + + env1 = new AuthZResource("env1", AuthZResource.Type.ENV); + envX = new AuthZResource("envX", AuthZResource.Type.ENV); + envStage = new AuthZResource("env1", AuthZResource.Type.ENV_STAGE); + envXStage = new AuthZResource("envX", AuthZResource.Type.ENV_STAGE); + } + + private void checkPositive( + TokenRolesBean bean, AuthZResource resource, TeletraanPrincipalRoles role) + throws Exception { + ScriptTokenPrincipal principal = + new ScriptTokenPrincipal<>( + "testPrincipal", + bean.getRole().getRole(), + new AuthZResource(bean.getResource_id(), bean.getResource_type())); + assertTrue(authorizer.authorize(principal, role.name(), resource, null)); + } + + private void checkNegative( + TokenRolesBean bean, AuthZResource resource, TeletraanPrincipalRoles requiredRole) + throws Exception { + ScriptTokenPrincipal principal = + new ScriptTokenPrincipal<>( + "testPrincipal", + bean.getRole().getRole(), + new AuthZResource(bean.getResource_id(), bean.getResource_type())); + assertFalse(authorizer.authorize(principal, requiredRole.name(), resource, null)); + } + + @Test + public void testSysEnv() throws Exception { + checkPositive(sysAdmin, env1, TeletraanPrincipalRoles.OPERATOR); + checkPositive(sysAdmin, env1, TeletraanPrincipalRoles.ADMIN); + + checkPositive(sysOperator, env1, TeletraanPrincipalRoles.OPERATOR); + checkNegative(sysOperator, env1, TeletraanPrincipalRoles.ADMIN); + + checkNegative(sysReader, env1, TeletraanPrincipalRoles.OPERATOR); + checkNegative(sysReader, env1, TeletraanPrincipalRoles.ADMIN); + } + + @Test + public void testSysSys() throws Exception { + checkPositive(sysAdmin, AuthZResource.SYSTEM_RESOURCE, TeletraanPrincipalRoles.OPERATOR); + checkPositive(sysAdmin, AuthZResource.SYSTEM_RESOURCE, TeletraanPrincipalRoles.ADMIN); + + checkPositive(sysOperator, AuthZResource.SYSTEM_RESOURCE, TeletraanPrincipalRoles.OPERATOR); + checkNegative(sysOperator, AuthZResource.SYSTEM_RESOURCE, TeletraanPrincipalRoles.ADMIN); + + checkNegative(sysReader, AuthZResource.SYSTEM_RESOURCE, TeletraanPrincipalRoles.OPERATOR); + checkNegative(sysReader, AuthZResource.SYSTEM_RESOURCE, TeletraanPrincipalRoles.ADMIN); + } + + @Test + public void testSysEnvStage() throws Exception { + checkPositive(sysAdmin, envStage, TeletraanPrincipalRoles.OPERATOR); + checkPositive(sysAdmin, envStage, TeletraanPrincipalRoles.ADMIN); + + checkPositive(sysOperator, envStage, TeletraanPrincipalRoles.OPERATOR); + checkNegative(sysOperator, envStage, TeletraanPrincipalRoles.ADMIN); + + checkNegative(sysReader, envStage, TeletraanPrincipalRoles.OPERATOR); + checkNegative(sysReader, envStage, TeletraanPrincipalRoles.ADMIN); + } + + @Test + public void testEnvSys() throws Exception { + checkNegative(envAdmin, AuthZResource.SYSTEM_RESOURCE, TeletraanPrincipalRoles.OPERATOR); + checkNegative(envAdmin, AuthZResource.SYSTEM_RESOURCE, TeletraanPrincipalRoles.ADMIN); + + checkNegative(envOperator, AuthZResource.SYSTEM_RESOURCE, TeletraanPrincipalRoles.OPERATOR); + checkNegative(envOperator, AuthZResource.SYSTEM_RESOURCE, TeletraanPrincipalRoles.ADMIN); + + checkNegative(envReader, AuthZResource.SYSTEM_RESOURCE, TeletraanPrincipalRoles.OPERATOR); + checkNegative(envReader, AuthZResource.SYSTEM_RESOURCE, TeletraanPrincipalRoles.ADMIN); + } + + @Test + public void testEnvXEnv1() throws Exception { + checkNegative(envAdmin, env1, TeletraanPrincipalRoles.OPERATOR); + checkNegative(envAdmin, env1, TeletraanPrincipalRoles.ADMIN); + + checkNegative(envOperator, env1, TeletraanPrincipalRoles.OPERATOR); + checkNegative(envOperator, env1, TeletraanPrincipalRoles.ADMIN); + + checkNegative(envReader, env1, TeletraanPrincipalRoles.OPERATOR); + checkNegative(envReader, env1, TeletraanPrincipalRoles.ADMIN); + } + + @Test + public void testEnvXEnvX() throws Exception { + checkPositive(envAdmin, envX, TeletraanPrincipalRoles.OPERATOR); + checkPositive(envAdmin, envX, TeletraanPrincipalRoles.ADMIN); + + checkPositive(envOperator, envX, TeletraanPrincipalRoles.OPERATOR); + checkNegative(envOperator, envX, TeletraanPrincipalRoles.ADMIN); + + checkNegative(envReader, envX, TeletraanPrincipalRoles.OPERATOR); + checkNegative(envReader, envX, TeletraanPrincipalRoles.ADMIN); + } + + @Test + public void testEnvXEnvStage() throws Exception { + checkNegative(envAdmin, envStage, TeletraanPrincipalRoles.OPERATOR); + checkNegative(envAdmin, envStage, TeletraanPrincipalRoles.ADMIN); + + checkNegative(envOperator, envStage, TeletraanPrincipalRoles.OPERATOR); + checkNegative(envOperator, envStage, TeletraanPrincipalRoles.ADMIN); + + checkNegative(envReader, envStage, TeletraanPrincipalRoles.OPERATOR); + checkNegative(envReader, envStage, TeletraanPrincipalRoles.ADMIN); + } + + @Test + public void testEnvXEnvXStage() throws Exception { + checkPositive(envAdmin, envXStage, TeletraanPrincipalRoles.OPERATOR); + checkPositive(envAdmin, envXStage, TeletraanPrincipalRoles.ADMIN); + + checkPositive(envOperator, envXStage, TeletraanPrincipalRoles.OPERATOR); + checkNegative(envOperator, envXStage, TeletraanPrincipalRoles.ADMIN); + + checkNegative(envReader, envXStage, TeletraanPrincipalRoles.OPERATOR); + checkNegative(envReader, envXStage, TeletraanPrincipalRoles.ADMIN); + } +} diff --git a/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/TeletraanScriptTokenProviderTest.java b/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/TeletraanScriptTokenProviderTest.java new file mode 100644 index 0000000000..862376f862 --- /dev/null +++ b/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/TeletraanScriptTokenProviderTest.java @@ -0,0 +1,60 @@ +package com.pinterest.teletraan.security; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Optional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import com.pinterest.deployservice.ServiceContext; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; +import com.pinterest.deployservice.bean.TokenRolesBean; +import com.pinterest.deployservice.dao.TokenRolesDAO; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; +import com.pinterest.teletraan.universal.security.bean.ScriptTokenPrincipal; +import com.pinterest.teletraan.universal.security.bean.ValueBasedRole; + +class TeletraanScriptTokenProviderTest { + private static final String GOOD_TOKEN = "goodToken"; + private ServiceContext context; + private TokenRolesDAO tokenRolesDAO; + private TeletraanScriptTokenProvider sut; + private TokenRolesBean tokenRolesBean; + + @BeforeEach + void setUp() throws Exception { + context = new ServiceContext(); + tokenRolesDAO = mock(TokenRolesDAO.class); + context.setTokenRolesDAO(tokenRolesDAO); + sut = new TeletraanScriptTokenProvider(context); + tokenRolesBean = new TokenRolesBean(); + tokenRolesBean.setScript_name("scriptName"); + tokenRolesBean.setResource_id("resourceId"); + tokenRolesBean.setRole(TeletraanPrincipalRoles.ADMIN); + tokenRolesBean.setResource_type(AuthZResource.Type.SYSTEM); + + when(tokenRolesDAO.getByToken(GOOD_TOKEN)).thenReturn(tokenRolesBean); + } + + @ParameterizedTest + @ValueSource(strings = { "", "badToken" }) + void testGetPrincipal_invalidToken(String token) { + Optional principal = sut.getPrincipal(token); + assertFalse(principal.isPresent()); + } + + @Test + void testGetPrincipal_validToken() { + ScriptTokenPrincipal principal = sut.getPrincipal(GOOD_TOKEN).get(); + assertEquals(TeletraanPrincipalRoles.ADMIN.getRole(), principal.getRole()); + assertEquals(AuthZResource.Type.SYSTEM, principal.getResource().getType()); + assertEquals(tokenRolesBean.getResource_id(), principal.getResource().getName()); + assertEquals(tokenRolesBean.getScript_name(), principal.getName()); + } +} diff --git a/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/UserRoleAuthorizerTest.java b/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/UserRoleAuthorizerTest.java new file mode 100644 index 0000000000..04eb107319 --- /dev/null +++ b/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/UserRoleAuthorizerTest.java @@ -0,0 +1,298 @@ +/** + * Copyright (c) 2016-2024 Pinterest, 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.pinterest.teletraan.security; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.when; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.core.MultivaluedHashMap; +import javax.ws.rs.core.MultivaluedMap; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mockito; + +import com.pinterest.deployservice.ServiceContext; +import com.pinterest.deployservice.bean.EnvironBean; +import com.pinterest.deployservice.bean.GroupRolesBean; +import com.pinterest.deployservice.bean.TeletraanPrincipalRoles; +import com.pinterest.deployservice.bean.UserRolesBean; +import com.pinterest.deployservice.dao.EnvironDAO; +import com.pinterest.deployservice.dao.GroupRolesDAO; +import com.pinterest.deployservice.dao.UserRolesDAO; +import com.pinterest.teletraan.universal.security.bean.AuthZResource; +import com.pinterest.teletraan.universal.security.bean.UserPrincipal; + +class UserRoleAuthorizerTest { + private static final String envXName = "envX"; + private static final String env1Name = "env1"; + private static final AuthZResource env1AuthZResource = new AuthZResource(env1Name, AuthZResource.Type.ENV_STAGE); + private static final AuthZResource envXAuthZResource = new AuthZResource(envXName, AuthZResource.Type.ENV_STAGE); + private static final AuthZResource ratingResource = new AuthZResource("rating", AuthZResource.Type.RATINGS); + private static final MultivaluedMap legacyToNewRoles = new MultivaluedHashMap<>(); + static AuthZResource[] resourceProvider() { + return new AuthZResource[] { + AuthZResource.SYSTEM_RESOURCE, + env1AuthZResource, + envXAuthZResource + }; + } + + private ServiceContext context; + private EnvironDAO environDAO; + private UserRolesDAO userRolesDAO; + private GroupRolesDAO groupRolesDAO; + + private UserRoleAuthorizer authorizer; + private UserPrincipal sysAdmin; + private UserPrincipal sysOperator; + private UserPrincipal sysReader; + private UserPrincipal sysAdminByGroup; + private UserPrincipal sysOperatorByGroup; + + private UserPrincipal sysReaderByGroup; + private UserPrincipal envAdmin; + private UserPrincipal envOperator; + private UserPrincipal envReader; + private UserPrincipal envAdminByGroup; + private UserPrincipal envOperatorByGroup; + + private UserPrincipal envReaderByGroup; + private String adminGroupName = "admin"; + private String operatorGroupName = "operator"; + + private String readerGroupName = "reader"; + + @BeforeAll + static void setUpAll() { + legacyToNewRoles.add(TeletraanPrincipalRoles.READER, TeletraanPrincipalRoles.READ); + legacyToNewRoles.add(TeletraanPrincipalRoles.OPERATOR, TeletraanPrincipalRoles.READ); + legacyToNewRoles.add(TeletraanPrincipalRoles.OPERATOR, TeletraanPrincipalRoles.WRITE); + legacyToNewRoles.add(TeletraanPrincipalRoles.OPERATOR, TeletraanPrincipalRoles.EXECUTE); + legacyToNewRoles.add(TeletraanPrincipalRoles.ADMIN, TeletraanPrincipalRoles.READ); + legacyToNewRoles.add(TeletraanPrincipalRoles.ADMIN, TeletraanPrincipalRoles.WRITE); + legacyToNewRoles.add(TeletraanPrincipalRoles.ADMIN, TeletraanPrincipalRoles.EXECUTE); + } + + @BeforeEach + void setUp() throws Exception { + context = new ServiceContext(); + userRolesDAO = Mockito.mock(UserRolesDAO.class); + groupRolesDAO = Mockito.mock(GroupRolesDAO.class); + environDAO = Mockito.mock(EnvironDAO.class); + context.setUserRolesDAO(userRolesDAO); + context.setGroupRolesDAO(groupRolesDAO); + context.setEnvironDAO(environDAO); + authorizer = new UserRoleAuthorizer(context, null); + + setUpUserPrincipals(); + setUpGroupRolesBeans(); + } + + @ParameterizedTest + @MethodSource("resourceProvider") + void testSystemUserOnResources(AuthZResource requestedResource) { + checkPositive(sysAdmin, requestedResource, TeletraanPrincipalRoles.READ); + checkPositive(sysAdmin, requestedResource, TeletraanPrincipalRoles.EXECUTE); + checkPositive(sysAdmin, requestedResource, TeletraanPrincipalRoles.WRITE); + + checkPositive(sysOperator, requestedResource, TeletraanPrincipalRoles.READ); + checkPositive(sysOperator, requestedResource, TeletraanPrincipalRoles.EXECUTE); + checkPositive(sysOperator, requestedResource, TeletraanPrincipalRoles.WRITE); + + checkPositive(sysReader, requestedResource, TeletraanPrincipalRoles.READ); + checkNegative(sysReader, requestedResource, TeletraanPrincipalRoles.EXECUTE); + checkNegative(sysReader, requestedResource, TeletraanPrincipalRoles.WRITE); + } + + @ParameterizedTest + @MethodSource("resourceProvider") + void testSystemUserOnResources_viaGroup(AuthZResource requestedResource) throws Exception { + GroupRolesBean sysAdminBean = createGroupRolesBean(TeletraanPrincipalRoles.ADMIN, adminGroupName); + when(groupRolesDAO.getByResource( + AuthZResource.ALL, AuthZResource.Type.SYSTEM)).thenReturn(Collections.singletonList(sysAdminBean)); + checkPositive(sysAdminByGroup, requestedResource, TeletraanPrincipalRoles.READ); + checkPositive(sysAdminByGroup, requestedResource, TeletraanPrincipalRoles.EXECUTE); + checkPositive(sysAdminByGroup, requestedResource, TeletraanPrincipalRoles.WRITE); + + GroupRolesBean sysOperatorBean = createGroupRolesBean(TeletraanPrincipalRoles.OPERATOR, operatorGroupName); + when(groupRolesDAO.getByResource( + AuthZResource.ALL, AuthZResource.Type.SYSTEM)).thenReturn(Collections.singletonList(sysOperatorBean)); + checkPositive(sysOperatorByGroup, requestedResource, TeletraanPrincipalRoles.READ); + checkPositive(sysOperatorByGroup, requestedResource, TeletraanPrincipalRoles.EXECUTE); + checkPositive(sysOperatorByGroup, requestedResource, TeletraanPrincipalRoles.WRITE); + + GroupRolesBean sysReaderBean = createGroupRolesBean(TeletraanPrincipalRoles.READER, readerGroupName); + when(groupRolesDAO.getByResource( + AuthZResource.ALL, AuthZResource.Type.SYSTEM)).thenReturn(Collections.singletonList(sysReaderBean)); + checkPositive(sysReaderByGroup, requestedResource, TeletraanPrincipalRoles.READ); + checkNegative(sysReaderByGroup, requestedResource, TeletraanPrincipalRoles.EXECUTE); + checkNegative(sysReaderByGroup, requestedResource, TeletraanPrincipalRoles.WRITE); + } + + @Test + void testEnvUserOnEnvResource() { + checkPositive(envAdmin, env1AuthZResource, TeletraanPrincipalRoles.READ); + checkPositive(envAdmin, env1AuthZResource, TeletraanPrincipalRoles.EXECUTE); + checkPositive(envAdmin, env1AuthZResource, TeletraanPrincipalRoles.WRITE); + + checkPositive(envOperator, env1AuthZResource, TeletraanPrincipalRoles.READ); + checkPositive(envOperator, env1AuthZResource, TeletraanPrincipalRoles.EXECUTE); + checkPositive(envOperator, env1AuthZResource, TeletraanPrincipalRoles.WRITE); + + checkPositive(envReader, env1AuthZResource, TeletraanPrincipalRoles.READ); + checkNegative(envReader, env1AuthZResource, TeletraanPrincipalRoles.EXECUTE); + checkNegative(envReader, env1AuthZResource, TeletraanPrincipalRoles.WRITE); + } + + @Test + void testEnvUserOnEnvXResource_viaGroup() throws Exception { + GroupRolesBean envAdminBean = createGroupRolesBean(TeletraanPrincipalRoles.ADMIN, adminGroupName); + when(groupRolesDAO.getByResource( + env1Name, AuthZResource.Type.ENV)).thenReturn(Collections.singletonList(envAdminBean)); + checkNegative(envAdminByGroup, envXAuthZResource, TeletraanPrincipalRoles.WRITE); + checkNegative(envAdminByGroup, envXAuthZResource, TeletraanPrincipalRoles.EXECUTE); + checkNegative(envAdminByGroup, envXAuthZResource, TeletraanPrincipalRoles.READ); + + GroupRolesBean envOperatorBean = createGroupRolesBean(TeletraanPrincipalRoles.OPERATOR, operatorGroupName); + when(groupRolesDAO.getByResource( + env1Name, AuthZResource.Type.ENV)).thenReturn(Collections.singletonList(envOperatorBean)); + checkNegative(envOperatorByGroup, envXAuthZResource, TeletraanPrincipalRoles.WRITE); + checkNegative(envOperatorByGroup, envXAuthZResource, TeletraanPrincipalRoles.EXECUTE); + checkNegative(envOperatorByGroup, envXAuthZResource, TeletraanPrincipalRoles.READ); + + GroupRolesBean envReaderBean = createGroupRolesBean(TeletraanPrincipalRoles.READER, readerGroupName); + when(groupRolesDAO.getByResource( + env1Name, AuthZResource.Type.ENV)).thenReturn(Collections.singletonList(envReaderBean)); + checkNegative(envReaderByGroup, envXAuthZResource, TeletraanPrincipalRoles.WRITE); + checkNegative(envReaderByGroup, envXAuthZResource, TeletraanPrincipalRoles.EXECUTE); + checkNegative(envReaderByGroup, envXAuthZResource, TeletraanPrincipalRoles.READ); + } + + @ParameterizedTest + @MethodSource("resourceProvider") + void testRandomUserOnDisallowedResources(AuthZResource requestedResource) { + UserPrincipal randomUser = new UserPrincipal("randomUser", Collections.singletonList("someGroup")); + checkNegative(randomUser, requestedResource, TeletraanPrincipalRoles.READ); + checkNegative(randomUser, requestedResource, TeletraanPrincipalRoles.EXECUTE); + checkNegative(randomUser, requestedResource, TeletraanPrincipalRoles.WRITE); + } + + @Test + void testRandomUserOnOtherResources() throws Exception { + UserPrincipal randomUser = new UserPrincipal("randomUser", Collections.singletonList("someGroup")); + checkPositive(randomUser, ratingResource, TeletraanPrincipalRoles.WRITE); + + when(environDAO.getByName(envXName)).thenReturn(null); + AuthZResource envXResource = new AuthZResource(envXName, AuthZResource.Type.ENV); + checkPositive(randomUser, envXResource, TeletraanPrincipalRoles.WRITE); + + when(environDAO.getByName(envXName)).thenReturn(Collections.singletonList(new EnvironBean())); + checkNegative(randomUser,envXResource, TeletraanPrincipalRoles.WRITE); + } + + @Test + void testRatingsResource() { + checkPositive(sysAdmin, ratingResource, TeletraanPrincipalRoles.WRITE); + checkPositive(sysOperator, ratingResource, TeletraanPrincipalRoles.WRITE); + checkPositive(sysReader, ratingResource, TeletraanPrincipalRoles.WRITE); + checkPositive(envAdmin, ratingResource, TeletraanPrincipalRoles.WRITE); + checkPositive(envOperator, ratingResource, TeletraanPrincipalRoles.WRITE); + checkPositive(envReader, ratingResource, TeletraanPrincipalRoles.WRITE); + } + + private void setUpGroupRolesBeans() throws Exception { + sysAdminByGroup = new UserPrincipal("sysAdminByGroup", Collections.singletonList(adminGroupName)); + sysOperatorByGroup = new UserPrincipal("sysOperatorByGroup", Collections.singletonList(operatorGroupName)); + sysReaderByGroup = new UserPrincipal("sysReaderByGroup", Collections.singletonList(readerGroupName)); + + envAdminByGroup = new UserPrincipal("env1AdminByGroup", Collections.singletonList(adminGroupName)); + envOperatorByGroup = new UserPrincipal("env1OperatorByGroup", + Collections.singletonList(operatorGroupName)); + envReaderByGroup = new UserPrincipal("env1ReaderByGroup", Collections.singletonList(readerGroupName)); + } + + private void setUpUserPrincipals() throws Exception { + UserRolesBean sysAdminBean = createUserRolesBean(TeletraanPrincipalRoles.ADMIN, "sysAdmin"); + when(userRolesDAO.getByNameAndResource( + sysAdminBean.getUser_name(), AuthZResource.ALL, AuthZResource.Type.SYSTEM)) + .thenReturn(sysAdminBean); + sysAdmin = new UserPrincipal("sysAdmin", null); + + UserRolesBean sysOperatorBean = createUserRolesBean(TeletraanPrincipalRoles.OPERATOR, "sysOperator"); + when(userRolesDAO.getByNameAndResource( + sysOperatorBean.getUser_name(), AuthZResource.ALL, AuthZResource.Type.SYSTEM)) + .thenReturn(sysOperatorBean); + sysOperator = new UserPrincipal("sysOperator", null); + + UserRolesBean sysReaderBean = createUserRolesBean(TeletraanPrincipalRoles.READER, "sysReader"); + when(userRolesDAO.getByNameAndResource( + sysReaderBean.getUser_name(), AuthZResource.ALL, AuthZResource.Type.SYSTEM)) + .thenReturn(sysReaderBean); + sysReader = new UserPrincipal("sysReader", null); + + UserRolesBean envAdminBean = createUserRolesBean(TeletraanPrincipalRoles.ADMIN, "env1Admin"); + when(userRolesDAO.getByNameAndResource( + envAdminBean.getUser_name(), env1Name, AuthZResource.Type.ENV)) + .thenReturn(envAdminBean); + envAdmin = new UserPrincipal("env1Admin", null); + + UserRolesBean envOperatorBean = createUserRolesBean(TeletraanPrincipalRoles.OPERATOR, "env1Operator"); + when(userRolesDAO.getByNameAndResource( + envOperatorBean.getUser_name(), env1Name, AuthZResource.Type.ENV)) + .thenReturn(envOperatorBean); + envOperator = new UserPrincipal("env1Operator", null); + + UserRolesBean envReaderBean = createUserRolesBean(TeletraanPrincipalRoles.READER, "env1Reader"); + when(userRolesDAO.getByNameAndResource( + envReaderBean.getUser_name(), env1Name, AuthZResource.Type.ENV)) + .thenReturn(envReaderBean); + envReader = new UserPrincipal("env1Reader", null); + } + + private UserRolesBean createUserRolesBean(TeletraanPrincipalRoles role, String userName) { + UserRolesBean userRolesBean = new UserRolesBean(); + userRolesBean.setRole(role); + userRolesBean.setUser_name(userName); + return userRolesBean; + } + + private GroupRolesBean createGroupRolesBean(TeletraanPrincipalRoles role, String groupName) { + GroupRolesBean groupRolesBean = new GroupRolesBean(); + groupRolesBean.setRole(role); + groupRolesBean.setGroup_name(groupName); + return groupRolesBean; + } + + private void checkPositive( + UserPrincipal user, AuthZResource requestedResource, TeletraanPrincipalRoles requiredRole) { + assertTrue(authorizer.authorize(user, requiredRole.name(), requestedResource, null)); + } + + private void checkNegative( + UserPrincipal user, AuthZResource requestedResource, TeletraanPrincipalRoles requiredRole) { + assertFalse(authorizer.authorize(user, requiredRole.name(), requestedResource, null)); + } +} diff --git a/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/UserTokenAuthorizerTest.java b/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/UserTokenAuthorizerTest.java deleted file mode 100644 index b7a06d0b3c..0000000000 --- a/deploy-service/teletraanservice/src/test/java/com/pinterest/teletraan/security/UserTokenAuthorizerTest.java +++ /dev/null @@ -1,171 +0,0 @@ -/** - * Copyright 2016 Pinterest, 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.pinterest.teletraan.security; - -import com.pinterest.deployservice.ServiceContext; -import com.pinterest.deployservice.bean.Resource; -import com.pinterest.deployservice.bean.Role; -import com.pinterest.deployservice.bean.UserRolesBean; -import com.pinterest.deployservice.dao.UserRolesDAO; -import com.pinterest.deployservice.exception.TeletaanInternalException; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import static org.junit.Assert.assertFalse; - -public class UserTokenAuthorizerTest { - private ServiceContext context; - private UserRolesDAO userRolesDAO; - private RoleAuthorizer authorizer; - - private UserRolesBean sysAdmin; - private UserRolesBean sysOperator; - private UserRolesBean sysReader; - - private UserRolesBean envAdmin; - private UserRolesBean envOperator; - private UserRolesBean envReader; - - private String envXName = "envX"; - private String env1Name = "env1"; - private Resource env1; - private Resource envX; - - @Before - public void setUp() throws Exception { - context = new ServiceContext(); - userRolesDAO = Mockito.mock(UserRolesDAO.class); - context.setUserRolesDAO(userRolesDAO); - authorizer = new RoleAuthorizer(context, null); - - sysAdmin = new UserRolesBean(); - sysAdmin.setRole(Role.ADMIN); - - sysOperator = new UserRolesBean(); - sysOperator.setRole(Role.OPERATOR); - - sysReader = new UserRolesBean(); - sysReader.setRole(Role.READER); - - envAdmin = new UserRolesBean(); - envAdmin.setRole(Role.ADMIN); - - envOperator = new UserRolesBean(); - envOperator.setRole(Role.OPERATOR); - - envReader = new UserRolesBean(); - envReader.setRole(Role.READER); - - env1 = new Resource(env1Name, Resource.Type.ENV); - envX = new Resource(envXName, Resource.Type.ENV); - } - - private void checkPositive(String userName, Resource resource, Role role) throws Exception { - authorizer.checkUserPermission(userName, resource, null, role); - } - - private void checkNegative(String userName, Resource resource, Role role) throws Exception { - try { - authorizer.checkUserPermission(userName, resource, null, role); - } catch (TeletaanInternalException e) { - // expected - return; - } - assertFalse("Expecting exception", true); - } - - @Test - public void testSysSys() throws Exception { - Mockito.when(userRolesDAO.getByNameAndResource(envXName, Resource.ALL, Resource.Type.SYSTEM)).thenReturn(sysAdmin); - checkPositive(envXName, Resource.SYSTEM_RESOURCE, Role.READER); - Mockito.when(userRolesDAO.getByNameAndResource(envXName, Resource.ALL, Resource.Type.SYSTEM)).thenReturn(sysAdmin); - checkPositive(envXName, Resource.SYSTEM_RESOURCE, Role.OPERATOR); - Mockito.when(userRolesDAO.getByNameAndResource(envXName, Resource.ALL, Resource.Type.SYSTEM)).thenReturn(sysAdmin); - checkPositive(envXName, Resource.SYSTEM_RESOURCE, Role.ADMIN); - - Mockito.when(userRolesDAO.getByNameAndResource(envXName, Resource.ALL, Resource.Type.SYSTEM)).thenReturn(sysOperator); - checkPositive(envXName, Resource.SYSTEM_RESOURCE, Role.READER); - Mockito.when(userRolesDAO.getByNameAndResource(envXName, Resource.ALL, Resource.Type.SYSTEM)).thenReturn(sysOperator); - checkPositive(envXName, Resource.SYSTEM_RESOURCE, Role.OPERATOR); - Mockito.when(userRolesDAO.getByNameAndResource(envXName, Resource.ALL, Resource.Type.SYSTEM)).thenReturn(sysOperator); - checkNegative(envXName, Resource.SYSTEM_RESOURCE, Role.ADMIN); - - Mockito.when(userRolesDAO.getByNameAndResource(envXName, Resource.ALL, Resource.Type.SYSTEM)).thenReturn(sysReader); - checkPositive(envXName, Resource.SYSTEM_RESOURCE, Role.READER); - Mockito.when(userRolesDAO.getByNameAndResource(envXName, Resource.ALL, Resource.Type.SYSTEM)).thenReturn(sysReader); - checkNegative(envXName, Resource.SYSTEM_RESOURCE, Role.OPERATOR); - Mockito.when(userRolesDAO.getByNameAndResource(envXName, Resource.ALL, Resource.Type.SYSTEM)).thenReturn(sysReader); - checkNegative(envXName, Resource.SYSTEM_RESOURCE, Role.ADMIN); - } - - @Test - public void testEnvSys() throws Exception { - Mockito.when(userRolesDAO.getByNameAndResource(envXName, Resource.ALL, Resource.Type.SYSTEM)).thenReturn(null); - checkNegative(envXName, Resource.SYSTEM_RESOURCE, Role.OPERATOR); - Mockito.when(userRolesDAO.getByNameAndResource(envXName, Resource.ALL, Resource.Type.SYSTEM)).thenReturn(null); - checkNegative(envXName, Resource.SYSTEM_RESOURCE, Role.ADMIN); - } - - @Test - public void testEnvXEnv1() throws Exception { - Mockito.when(userRolesDAO.getByNameAndResource(envXName, env1Name, Resource.Type.ENV)).thenReturn(null); - Mockito.when(userRolesDAO.getByNameAndResource(envXName, Resource.ALL, Resource.Type.SYSTEM)).thenReturn(null); - checkNegative(envXName, env1, Role.OPERATOR); - Mockito.when(userRolesDAO.getByNameAndResource(envXName, env1Name, Resource.Type.ENV)).thenReturn(null); - Mockito.when(userRolesDAO.getByNameAndResource(envXName, Resource.ALL, Resource.Type.SYSTEM)).thenReturn(sysAdmin); - checkPositive(envXName, env1, Role.ADMIN); - } - - @Test - public void testEnvXEnvX() throws Exception { - Mockito.when(userRolesDAO.getByNameAndResource(envXName, envXName, Resource.Type.ENV)).thenReturn(envAdmin); - checkPositive(envXName, envX, Role.OPERATOR); - Mockito.when(userRolesDAO.getByNameAndResource(envXName, envXName, Resource.Type.ENV)).thenReturn(envAdmin); - checkPositive(envXName, envX, Role.ADMIN); - - Mockito.when(userRolesDAO.getByNameAndResource(envXName, envXName, Resource.Type.ENV)).thenReturn(envOperator); - checkPositive(envXName, envX, Role.OPERATOR); - Mockito.when(userRolesDAO.getByNameAndResource(envXName, envXName, Resource.Type.ENV)).thenReturn(envOperator); - checkNegative(envXName, envX, Role.ADMIN); - - Mockito.when(userRolesDAO.getByNameAndResource(envXName, envXName, Resource.Type.ENV)).thenReturn(envReader); - checkNegative(envXName, envX, Role.OPERATOR); - Mockito.when(userRolesDAO.getByNameAndResource(envXName, envXName, Resource.Type.ENV)).thenReturn(envReader); - checkNegative(envXName, envX, Role.ADMIN); - } - - @Test - public void testSysEnvX() throws Exception { - Mockito.when(userRolesDAO.getByNameAndResource(envXName, envXName, Resource.Type.ENV)).thenReturn(envAdmin); - checkPositive(envXName, envX, Role.OPERATOR); - Mockito.when(userRolesDAO.getByNameAndResource(envXName, envXName, Resource.Type.ENV)).thenReturn(envAdmin); - checkPositive(envXName, envX, Role.ADMIN); - - Mockito.when(userRolesDAO.getByNameAndResource(envXName, envXName, Resource.Type.ENV)).thenReturn(envOperator); - checkPositive(envXName, envX, Role.OPERATOR); - Mockito.when(userRolesDAO.getByNameAndResource(envXName, envXName, Resource.Type.ENV)).thenReturn(envOperator); - Mockito.when(userRolesDAO.getByNameAndResource(envXName, Resource.ALL, Resource.Type.SYSTEM)).thenReturn(sysAdmin); - checkPositive(envXName, envX, Role.ADMIN); - - Mockito.when(userRolesDAO.getByNameAndResource(envXName, envXName, Resource.Type.ENV)).thenReturn(envReader); - Mockito.when(userRolesDAO.getByNameAndResource(envXName, Resource.ALL, Resource.Type.SYSTEM)).thenReturn(null); - checkNegative(envXName, envX, Role.OPERATOR); - Mockito.when(userRolesDAO.getByNameAndResource(envXName, envXName, Resource.Type.ENV)).thenReturn(envReader); - Mockito.when(userRolesDAO.getByNameAndResource(envXName, Resource.ALL, Resource.Type.SYSTEM)).thenReturn(sysOperator); - checkNegative(envXName, envX, Role.ADMIN); - } -}