Skip to content

Commit

Permalink
Merge pull request #23 from yahoo/rolemember
Browse files Browse the repository at this point in the history
Support for temporary role members
  • Loading branch information
havetisyan authored Feb 8, 2017
2 parents 8820f08 + f9fc02b commit c6c5331
Show file tree
Hide file tree
Showing 39 changed files with 2,248 additions and 1,101 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
**/target/
**/dependency-reduced-pom.xml
**/pom.xml.releaseBackup
ui/.eslintcodecache
release.properties
servers/zms/zms_logs/
servers/zms/zms_root/
Expand Down
70 changes: 70 additions & 0 deletions clients/go/zms/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,66 @@ func (pTypeDef *RoleAuditLog) Validate() error {
return nil
}

//
// RoleMember -
//
type RoleMember struct {

//
// name of the member
//
MemberName ResourceName `json:"memberName"`

//
// the expiration timestamp
//
Expiration *rdl.Timestamp `json:"expiration,omitempty" rdl:"optional"`
}

//
// NewRoleMember - creates an initialized RoleMember instance, returns a pointer to it
//
func NewRoleMember(init ...*RoleMember) *RoleMember {
var o *RoleMember
if len(init) == 1 {
o = init[0]
} else {
o = new(RoleMember)
}
return o
}

type rawRoleMember RoleMember

//
// UnmarshalJSON is defined for proper JSON decoding of a RoleMember
//
func (pTypeDef *RoleMember) UnmarshalJSON(b []byte) error {
var r rawRoleMember
err := json.Unmarshal(b, &r)
if err == nil {
o := RoleMember(r)
*pTypeDef = o
err = pTypeDef.Validate()
}
return err
}

//
// Validate - checks for missing required fields, etc
//
func (pTypeDef *RoleMember) Validate() error {
if pTypeDef.MemberName == "" {
return fmt.Errorf("RoleMember.memberName is missing but is a required field")
} else {
val := rdl.Validate(ZMSSchema(), "ResourceName", pTypeDef.MemberName)
if !val.Valid {
return fmt.Errorf("RoleMember.memberName does not contain a valid ResourceName (%v)", val.Error)
}
}
return nil
}

//
// Role - The representation for a Role with set of members.
//
Expand All @@ -393,6 +453,11 @@ type Role struct {
//
Members []ResourceName `json:"members,omitempty" rdl:"optional"`

//
// members with expiration
//
RoleMembers []*RoleMember `json:"roleMembers,omitempty" rdl:"optional"`

//
// a trusted domain to delegate membership decisions to
//
Expand Down Expand Up @@ -527,6 +592,11 @@ type Membership struct {
// name of the role
//
RoleName ResourceName `json:"roleName,omitempty" rdl:"optional"`

//
// the expiration timestamp
//
Expiration *rdl.Timestamp `json:"expiration,omitempty" rdl:"optional"`
}

//
Expand Down
7 changes: 7 additions & 0 deletions clients/go/zms/zms_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,17 @@ func init() {
tRoleAuditLog.Field("auditRef", "String", true, nil, "audit reference string for the change as supplied by admin")
sb.AddType(tRoleAuditLog.Build())

tRoleMember := rdl.NewStructTypeBuilder("Struct", "RoleMember")
tRoleMember.Field("memberName", "ResourceName", false, nil, "name of the member")
tRoleMember.Field("expiration", "Timestamp", true, nil, "the expiration timestamp")
sb.AddType(tRoleMember.Build())

tRole := rdl.NewStructTypeBuilder("Struct", "Role")
tRole.Comment("The representation for a Role with set of members.")
tRole.Field("name", "ResourceName", false, nil, "name of the role")
tRole.Field("modified", "Timestamp", true, nil, "last modification timestamp of the role")
tRole.ArrayField("members", "ResourceName", true, "an explicit list of members. Might be empty or null, if trust is set")
tRole.ArrayField("roleMembers", "RoleMember", true, "members with expiration")
tRole.Field("trust", "DomainName", true, nil, "a trusted domain to delegate membership decisions to")
tRole.ArrayField("auditLog", "RoleAuditLog", true, "an audit log for role membership changes")
sb.AddType(tRole.Build())
Expand All @@ -128,6 +134,7 @@ func init() {
tMembership.Field("memberName", "ResourceName", false, nil, "name of the member")
tMembership.Field("isMember", "Bool", true, true, "flag to indicate whether or the user is a member or not")
tMembership.Field("roleName", "ResourceName", true, nil, "name of the role")
tMembership.Field("expiration", "Timestamp", true, nil, "the expiration timestamp")
sb.AddType(tMembership.Build())

tDefaultAdmins := rdl.NewStructTypeBuilder("Struct", "DefaultAdmins")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import com.yahoo.athenz.auth.token.PrincipalToken;
import com.yahoo.athenz.common.config.AthenzConfig;
import com.yahoo.rdl.JSON;
import com.yahoo.rdl.Timestamp;

public class ZMSClient implements Closeable {

Expand Down Expand Up @@ -656,11 +657,25 @@ public Membership getMembership(String domainName, String roleName, String membe
* @param auditRef string containing audit specification or ticket number
*/
public void putMembership(String domainName, String roleName, String memberName, String auditRef) {
updatePrincipal();
putMembership(domainName, roleName, memberName, null, auditRef);
}

/**
* Add a temporary member in the specified role with expiration
* @param domainName name of the domain
* @param roleName name of the role
* @param memberName name of the member to be added
* @param expiration timestamp when this membership will expire (optional)
* @param auditRef string containing audit specification or ticket number
*/
public void putMembership(String domainName, String roleName, String memberName,
Timestamp expiration, String auditRef) {
Membership mbr = new Membership();
mbr.setRoleName(roleName);
mbr.setMemberName(memberName);
mbr.setExpiration(expiration);
mbr.setIsMember(true);
updatePrincipal();
try {
client.putMembership(domainName, roleName, memberName, auditRef, mbr);
} catch (ResourceException ex) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.yahoo.athenz.auth.impl.SimplePrincipal;
import com.yahoo.rdl.Array;
import com.yahoo.rdl.Struct;
import com.yahoo.rdl.Timestamp;

import static org.testng.Assert.*;

Expand Down Expand Up @@ -421,16 +422,27 @@ private void testAddMembership(ZMSClient client, String adminUser) {
Role role1 = createRoleObject(client, "MbrAddDom1", "Role1", null, "user.joe", "user.jane");
client.putRole("MbrAddDom1", "Role1", AUDIT_REF, role1);
client.putMembership("MbrAddDom1", "Role1", "user.doe", AUDIT_REF);

client.putMembership("MbrAddDom1", "Role1", "user.temp",
Timestamp.fromMillis(100000), AUDIT_REF);
Role role = client.getRole("MbrAddDom1", "Role1");
assertNotNull(role);

List<String> members = role.getMembers();
List<RoleMember> members = role.getRoleMembers();
assertNotNull(members);
assertEquals(members.size(), 3);

assertTrue(members.contains("user.joe"));
assertTrue(members.contains("user.jane"));
assertTrue(members.contains("user.doe"));
assertEquals(members.size(), 4);

boolean userTempCheck = false;
boolean userDoeCheck = false;
for (RoleMember member: members) {
if (member.getMemberName().equals("user.temp")) {
userTempCheck = true;
} else if (member.getMemberName().equals("user.doe")) {
userDoeCheck = true;
}
}
assertTrue(userTempCheck);
assertTrue(userDoeCheck);

client.deleteTopLevelDomain("MbrAddDom1", AUDIT_REF);
}
Expand Down Expand Up @@ -1746,14 +1758,22 @@ public void testAddMembershipUserToken() {
mbr.setRoleName("Role1");
mbr.setMemberName("user.doe");
mbr.setIsMember(true);
Membership mbrExp = new Membership();
mbrExp.setRoleName("Role1");
mbrExp.setMemberName("user.temp");
mbrExp.setExpiration(Timestamp.fromMillis(100000));
mbrExp.setIsMember(true);
Membership membershipMock = Mockito.mock(Membership.class);
Mockito.when(c.putMembership("MbrAddDom1", "Role1", "user.doe", AUDIT_REF, mbr)).thenReturn(membershipMock);
Mockito.when(c.putMembership("MbrAddDom1", "Role1", "user.temp", AUDIT_REF, mbrExp)).thenReturn(membershipMock);
Mockito.when(c.getRole("MbrAddDom1", "Role1", false, false)).thenReturn(roleMock);
@SuppressWarnings("unchecked")
List<String> membersMock = Mockito.mock(List.class);
Mockito.when(roleMock.getMembers()).thenReturn(membersMock);
Mockito.when(membersMock.size()).thenReturn(3);
Mockito.when(membersMock.contains(Mockito.anyString())).thenReturn(true);
List<RoleMember> roleMembers = new ArrayList<>();
roleMembers.add(new RoleMember().setMemberName("user.joe"));
roleMembers.add(new RoleMember().setMemberName("user.jane"));
roleMembers.add(new RoleMember().setMemberName("user.doe"));
roleMembers.add(new RoleMember().setMemberName("user.temp")
.setExpiration(Timestamp.fromMillis(100000)));
Mockito.when(roleMock.getRoleMembers()).thenReturn(roleMembers);
testAddMembership(client, systemAdminFullUser);
Mockito.when(c.deleteTopLevelDomain("MbrGetRoleDom1", AUDIT_REF)).thenReturn(dom1Mock);
}
Expand Down
12 changes: 12 additions & 0 deletions core/zms/src/main/java/com/yahoo/athenz/zms/Membership.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public class Membership {
public Boolean isMember;
@RdlOptional
public String roleName;
@RdlOptional
public Timestamp expiration;

public Membership setMemberName(String memberName) {
this.memberName = memberName;
Expand All @@ -38,6 +40,13 @@ public Membership setRoleName(String roleName) {
public String getRoleName() {
return roleName;
}
public Membership setExpiration(Timestamp expiration) {
this.expiration = expiration;
return this;
}
public Timestamp getExpiration() {
return expiration;
}

@Override
public boolean equals(Object another) {
Expand All @@ -55,6 +64,9 @@ public boolean equals(Object another) {
if (roleName == null ? a.roleName != null : !roleName.equals(a.roleName)) {
return false;
}
if (expiration == null ? a.expiration != null : !expiration.equals(a.expiration)) {
return false;
}
}
return true;
}
Expand Down
12 changes: 12 additions & 0 deletions core/zms/src/main/java/com/yahoo/athenz/zms/Role.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public class Role {
@RdlOptional
public List<String> members;
@RdlOptional
public List<RoleMember> roleMembers;
@RdlOptional
public String trust;
@RdlOptional
public List<RoleAuditLog> auditLog;
Expand All @@ -43,6 +45,13 @@ public Role setMembers(List<String> members) {
public List<String> getMembers() {
return members;
}
public Role setRoleMembers(List<RoleMember> roleMembers) {
this.roleMembers = roleMembers;
return this;
}
public List<RoleMember> getRoleMembers() {
return roleMembers;
}
public Role setTrust(String trust) {
this.trust = trust;
return this;
Expand Down Expand Up @@ -74,6 +83,9 @@ public boolean equals(Object another) {
if (members == null ? a.members != null : !members.equals(a.members)) {
return false;
}
if (roleMembers == null ? a.roleMembers != null : !roleMembers.equals(a.roleMembers)) {
return false;
}
if (trust == null ? a.trust != null : !trust.equals(a.trust)) {
return false;
}
Expand Down
49 changes: 49 additions & 0 deletions core/zms/src/main/java/com/yahoo/athenz/zms/RoleMember.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// This file generated by rdl 1.4.10. Do not modify!
//

package com.yahoo.athenz.zms;
import com.yahoo.rdl.*;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

//
// RoleMember -
//
@JsonSerialize(include = JsonSerialize.Inclusion.NON_DEFAULT)
public class RoleMember {
public String memberName;
@RdlOptional
public Timestamp expiration;

public RoleMember setMemberName(String memberName) {
this.memberName = memberName;
return this;
}
public String getMemberName() {
return memberName;
}
public RoleMember setExpiration(Timestamp expiration) {
this.expiration = expiration;
return this;
}
public Timestamp getExpiration() {
return expiration;
}

@Override
public boolean equals(Object another) {
if (this != another) {
if (another == null || another.getClass() != RoleMember.class) {
return false;
}
RoleMember a = (RoleMember) another;
if (memberName == null ? a.memberName != null : !memberName.equals(a.memberName)) {
return false;
}
if (expiration == null ? a.expiration != null : !expiration.equals(a.expiration)) {
return false;
}
}
return true;
}
}
8 changes: 7 additions & 1 deletion core/zms/src/main/java/com/yahoo/athenz/zms/ZMSSchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,16 @@ private static Schema build() {
.field("action", "String", false, "log action - either add or delete")
.field("auditRef", "String", true, "audit reference string for the change as supplied by admin");

sb.structType("RoleMember")
.field("memberName", "ResourceName", false, "name of the member")
.field("expiration", "Timestamp", true, "the expiration timestamp");

sb.structType("Role")
.comment("The representation for a Role with set of members.")
.field("name", "ResourceName", false, "name of the role")
.field("modified", "Timestamp", true, "last modification timestamp of the role")
.arrayField("members", "ResourceName", true, "an explicit list of members. Might be empty or null, if trust is set")
.arrayField("roleMembers", "RoleMember", true, "members with expiration")
.field("trust", "DomainName", true, "a trusted domain to delegate membership decisions to")
.arrayField("auditLog", "RoleAuditLog", true, "an audit log for role membership changes");

Expand All @@ -111,7 +116,8 @@ private static Schema build() {
.comment("The representation for a role membership.")
.field("memberName", "ResourceName", false, "name of the member")
.field("isMember", "Bool", false, "flag to indicate whether or the user is a member or not", true)
.field("roleName", "ResourceName", true, "name of the role");
.field("roleName", "ResourceName", true, "name of the role")
.field("expiration", "Timestamp", true, "the expiration timestamp");

sb.structType("DefaultAdmins")
.comment("The list of domain administrators.")
Expand Down
7 changes: 7 additions & 0 deletions core/zms/src/main/rdl/Role.tdl
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,17 @@ type RoleAuditLog Struct {
String auditRef (optional); //audit reference string for the change as supplied by admin
}

type RoleMember Struct {
ResourceName memberName; //name of the member
Timestamp expiration (optional); //the expiration timestamp
}

//The representation for a Role with set of members.
type Role Struct {
ResourceName name; //name of the role
Timestamp modified (optional); //last modification timestamp of the role
Array<ResourceName> members (optional); //an explicit list of members. Might be empty or null, if trust is set
Array<RoleMember> roleMembers (optional); //members with expiration
DomainName trust (optional); //a trusted domain to delegate membership decisions to
Array<RoleAuditLog> auditLog (optional); //an audit log for role membership changes
}
Expand All @@ -37,6 +43,7 @@ type Membership Struct {
ResourceName memberName; //name of the member
Bool isMember (optional, default=true); //flag to indicate whether or the user is a member or not
ResourceName roleName (optional); //name of the role
Timestamp expiration (optional); //the expiration timestamp
}

//The list of domain administrators.
Expand Down
Loading

0 comments on commit c6c5331

Please sign in to comment.