Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(iam): add imported user to a group #13698

Merged
merged 8 commits into from Apr 22, 2021
12 changes: 12 additions & 0 deletions packages/@aws-cdk/aws-iam/README.md
Expand Up @@ -433,6 +433,18 @@ const user = User.fromUserAttributes(stack, 'MyImportedUserByAttributes', {
});
```

To add a user to a group (both for a new and imported user/group):

```ts
const user = new User(this, 'MyUser'); // or User.fromUserName(stack, 'User', 'johnsmith');
const group = new Group(this, 'MyGroup'); // or Group.fromGroupArn(stack, 'Group', 'arn:aws:iam::account-id:group/group-name');

user.addToGroup(group);
// or
group.addUser(user);
```


## Features

* Policy name uniqueness is enforced. If two policies by the same name are attached to the same
Expand Down
13 changes: 9 additions & 4 deletions packages/@aws-cdk/aws-iam/lib/user.ts
@@ -1,7 +1,7 @@
import { Arn, Aws, Lazy, Resource, SecretValue, Stack } from '@aws-cdk/core';
import { Construct } from 'constructs';
import { IGroup } from './group';
import { CfnUser } from './iam.generated';
import { CfnUser, CfnUserToGroupAddition } from './iam.generated';
import { IIdentity } from './identity-base';
import { IManagedPolicy } from './managed-policy';
import { Policy } from './policy';
Expand Down Expand Up @@ -181,6 +181,7 @@ export class User extends Resource implements IIdentity, IUser {
public readonly policyFragment: PrincipalPolicyFragment = new ArnPrincipal(attrs.userArn).policyFragment;
private readonly attachedPolicies = new AttachedPolicies();
private defaultPolicy?: Policy;
private groupId = 0;

public addToPolicy(statement: PolicyStatement): boolean {
return this.addToPrincipalPolicy(statement).statementAdded;
Expand All @@ -195,8 +196,12 @@ export class User extends Resource implements IIdentity, IUser {
return { statementAdded: true, policyDependable: this.defaultPolicy };
}

public addToGroup(_group: IGroup): void {
throw new Error('Cannot add imported User to Group');
public addToGroup(group: IGroup): void {
new CfnUserToGroupAddition(Stack.of(group), `${this.userName}Group${this.groupId}`, {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woooaahhhh

groupName: group.groupName,
users: [this.userName],
});
this.groupId += 1;
}

public attachInlinePolicy(policy: Policy): void {
Expand Down Expand Up @@ -229,7 +234,7 @@ export class User extends Resource implements IIdentity, IUser {
public readonly userArn: string;

/**
* Returns the permissions boundary attached to this user
* Returns the permissions boundary attached to this user
*/
public readonly permissionsBoundary?: IManagedPolicy;

Expand Down
33 changes: 32 additions & 1 deletion packages/@aws-cdk/aws-iam/test/user.test.ts
@@ -1,6 +1,6 @@
import '@aws-cdk/assert/jest';
import { App, SecretValue, Stack } from '@aws-cdk/core';
import { ManagedPolicy, Policy, PolicyStatement, User } from '../lib';
import { Group, ManagedPolicy, Policy, PolicyStatement, User } from '../lib';

describe('IAM user', () => {
test('default user', () => {
Expand Down Expand Up @@ -177,4 +177,35 @@ describe('IAM user', () => {
},
});
});

test('addToGroup for imported user', () => {
// GIVEN
const stack = new Stack();
const user = User.fromUserName(stack, 'ImportedUser', 'john');
const group = new Group(stack, 'Group');
const otherGroup = new Group(stack, 'OtherGroup');

// WHEN
user.addToGroup(group);
otherGroup.addUser(user);

// THEN
expect(stack).toHaveResource('AWS::IAM::UserToGroupAddition', {
GroupName: {
Ref: 'GroupC77FDACD',
},
Users: [
'john',
],
});

expect(stack).toHaveResource('AWS::IAM::UserToGroupAddition', {
GroupName: {
Ref: 'OtherGroup85E5C653',
},
Users: [
'john',
],
});
});
});