-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #652 from ajkannan/iam
Create IAM Policy classes
- Loading branch information
Showing
7 changed files
with
989 additions
and
1 deletion.
There are no files selected for viewing
256 changes: 256 additions & 0 deletions
256
gcloud-java-core/src/main/java/com/google/gcloud/IamPolicy.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,256 @@ | ||
/* | ||
* Copyright 2016 Google Inc. All Rights Reserved. | ||
* | ||
* 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.google.gcloud; | ||
|
||
import static com.google.common.base.Preconditions.checkArgument; | ||
|
||
import com.google.common.collect.ImmutableMap; | ||
import com.google.common.collect.ImmutableSet; | ||
|
||
import java.io.Serializable; | ||
import java.util.Arrays; | ||
import java.util.Collection; | ||
import java.util.HashMap; | ||
import java.util.HashSet; | ||
import java.util.LinkedList; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
import java.util.Set; | ||
|
||
/** | ||
* Base class for Identity and Access Management (IAM) policies. IAM policies are used to specify | ||
* access settings for Cloud Platform resources. A policy is a map of bindings. A binding assigns | ||
* a set of identities to a role, where the identities can be user accounts, Google groups, Google | ||
* domains, and service accounts. A role is a named list of permissions defined by IAM. | ||
* | ||
* @param <R> the data type of roles (should be serializable) | ||
* @see <a href="https://cloud.google.com/iam/reference/rest/v1/Policy">Policy</a> | ||
*/ | ||
public abstract class IamPolicy<R> implements Serializable { | ||
|
||
private static final long serialVersionUID = 1114489978726897720L; | ||
|
||
private final Map<R, Set<Identity>> bindings; | ||
private final String etag; | ||
private final Integer version; | ||
|
||
/** | ||
* Builder for an IAM Policy. | ||
* | ||
* @param <R> the data type of roles | ||
* @param <B> the subclass extending this abstract builder | ||
*/ | ||
public abstract static class Builder<R, B extends Builder<R, B>> { | ||
|
||
private final Map<R, Set<Identity>> bindings = new HashMap<>(); | ||
private String etag; | ||
private Integer version; | ||
|
||
/** | ||
* Constructor for IAM Policy builder. | ||
*/ | ||
protected Builder() {} | ||
|
||
/** | ||
* Replaces the builder's map of bindings with the given map of bindings. | ||
* | ||
* @throws IllegalArgumentException if the provided map is null or contain any null values | ||
*/ | ||
public final B bindings(Map<R, Set<Identity>> bindings) { | ||
checkArgument(bindings != null, "The provided map of bindings cannot be null."); | ||
for (Map.Entry<R, Set<Identity>> binding : bindings.entrySet()) { | ||
verifyBinding(binding.getKey(), binding.getValue()); | ||
} | ||
this.bindings.clear(); | ||
for (Map.Entry<R, Set<Identity>> binding : bindings.entrySet()) { | ||
this.bindings.put(binding.getKey(), new HashSet<Identity>(binding.getValue())); | ||
} | ||
return self(); | ||
} | ||
|
||
/** | ||
* Adds a binding to the policy. | ||
* | ||
* @throws IllegalArgumentException if the policy already contains a binding with the same role | ||
* or if the role or any identities are null | ||
*/ | ||
public final B addBinding(R role, Set<Identity> identities) { | ||
verifyBinding(role, identities); | ||
checkArgument(!bindings.containsKey(role), | ||
"The policy already contains a binding with the role " + role.toString() + "."); | ||
bindings.put(role, new HashSet<Identity>(identities)); | ||
return self(); | ||
} | ||
|
||
/** | ||
* Adds a binding to the policy. | ||
* | ||
* @throws IllegalArgumentException if the policy already contains a binding with the same role | ||
* or if the role or any identities are null | ||
*/ | ||
public final B addBinding(R role, Identity first, Identity... others) { | ||
HashSet<Identity> identities = new HashSet<>(); | ||
identities.add(first); | ||
identities.addAll(Arrays.asList(others)); | ||
return addBinding(role, identities); | ||
} | ||
|
||
private void verifyBinding(R role, Collection<Identity> identities) { | ||
checkArgument(role != null, "The role cannot be null."); | ||
verifyIdentities(identities); | ||
} | ||
|
||
private void verifyIdentities(Collection<Identity> identities) { | ||
checkArgument(identities != null, "A role cannot be assigned to a null set of identities."); | ||
checkArgument(!identities.contains(null), "Null identities are not permitted."); | ||
} | ||
|
||
/** | ||
* Removes the binding associated with the specified role. | ||
*/ | ||
public final B removeBinding(R role) { | ||
bindings.remove(role); | ||
return self(); | ||
} | ||
|
||
/** | ||
* Adds one or more identities to an existing binding. | ||
* | ||
* @throws IllegalArgumentException if the policy doesn't contain a binding with the specified | ||
* role or any identities are null | ||
*/ | ||
public final B addIdentity(R role, Identity first, Identity... others) { | ||
checkArgument(bindings.containsKey(role), | ||
"The policy doesn't contain the role " + role.toString() + "."); | ||
List<Identity> toAdd = new LinkedList<>(); | ||
toAdd.add(first); | ||
toAdd.addAll(Arrays.asList(others)); | ||
verifyIdentities(toAdd); | ||
bindings.get(role).addAll(toAdd); | ||
return self(); | ||
} | ||
|
||
/** | ||
* Removes one or more identities from an existing binding. | ||
* | ||
* @throws IllegalArgumentException if the policy doesn't contain a binding with the specified | ||
* role | ||
*/ | ||
public final B removeIdentity(R role, Identity first, Identity... others) { | ||
checkArgument(bindings.containsKey(role), | ||
"The policy doesn't contain the role " + role.toString() + "."); | ||
bindings.get(role).remove(first); | ||
bindings.get(role).removeAll(Arrays.asList(others)); | ||
return self(); | ||
} | ||
|
||
/** | ||
* Sets the policy's etag. | ||
* | ||
* <p>Etags are used for optimistic concurrency control as a way to help prevent simultaneous | ||
* updates of a policy from overwriting each other. It is strongly suggested that systems make | ||
* use of the etag in the read-modify-write cycle to perform policy updates in order to avoid | ||
* race conditions. An etag is returned in the response to getIamPolicy, and systems are | ||
* expected to put that etag in the request to setIamPolicy to ensure that their change will be | ||
* applied to the same version of the policy. If no etag is provided in the call to | ||
* setIamPolicy, then the existing policy is overwritten blindly. | ||
*/ | ||
protected final B etag(String etag) { | ||
this.etag = etag; | ||
return self(); | ||
} | ||
|
||
/** | ||
* Sets the version of the policy. The default version is 0, meaning only the "owner", "editor", | ||
* and "viewer" roles are permitted. If the version is 1, you may also use other roles. | ||
*/ | ||
protected final B version(Integer version) { | ||
this.version = version; | ||
return self(); | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
private B self() { | ||
return (B) this; | ||
} | ||
|
||
public abstract IamPolicy<R> build(); | ||
} | ||
|
||
protected IamPolicy(Builder<R, ? extends Builder<R, ?>> builder) { | ||
ImmutableMap.Builder<R, Set<Identity>> bindingsBuilder = ImmutableMap.builder(); | ||
for (Map.Entry<R, Set<Identity>> binding : builder.bindings.entrySet()) { | ||
bindingsBuilder.put(binding.getKey(), ImmutableSet.copyOf(binding.getValue())); | ||
} | ||
this.bindings = bindingsBuilder.build(); | ||
this.etag = builder.etag; | ||
this.version = builder.version; | ||
} | ||
|
||
/** | ||
* Returns a builder containing the properties of this IAM Policy. | ||
*/ | ||
public abstract Builder<R, ? extends Builder<R, ?>> toBuilder(); | ||
|
||
/** | ||
* The map of bindings that comprises the policy. | ||
*/ | ||
public Map<R, Set<Identity>> bindings() { | ||
return bindings; | ||
} | ||
|
||
/** | ||
* The policy's etag. | ||
* | ||
* <p>Etags are used for optimistic concurrency control as a way to help prevent simultaneous | ||
* updates of a policy from overwriting each other. It is strongly suggested that systems make | ||
* use of the etag in the read-modify-write cycle to perform policy updates in order to avoid | ||
* race conditions. An etag is returned in the response to getIamPolicy, and systems are | ||
* expected to put that etag in the request to setIamPolicy to ensure that their change will be | ||
* applied to the same version of the policy. If no etag is provided in the call to | ||
* setIamPolicy, then the existing policy is overwritten blindly. | ||
*/ | ||
public String etag() { | ||
return etag; | ||
} | ||
|
||
/** | ||
* Sets the version of the policy. The default version is 0, meaning only the "owner", "editor", | ||
* and "viewer" roles are permitted. If the version is 1, you may also use other roles. | ||
*/ | ||
public Integer version() { | ||
return version; | ||
} | ||
|
||
@Override | ||
public final int hashCode() { | ||
return Objects.hash(getClass(), bindings, etag, version); | ||
} | ||
|
||
@Override | ||
public final boolean equals(Object obj) { | ||
if (obj == null || !getClass().equals(obj.getClass())) { | ||
return false; | ||
} | ||
@SuppressWarnings("rawtypes") | ||
IamPolicy other = (IamPolicy) obj; | ||
return Objects.equals(bindings, other.bindings()) | ||
&& Objects.equals(etag, other.etag()) | ||
&& Objects.equals(version, other.version()); | ||
} | ||
} |
Oops, something went wrong.