/**
* Copyright (C) 2015 Zalando SE (http://tech.zalando.com)
*
* 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 org.zalando.stups.tokens;
import static org.zalando.stups.tokens.util.Objects.noBlankEntries;
import static org.zalando.stups.tokens.util.Objects.noNullEntries;
import static org.zalando.stups.tokens.util.Objects.notBlank;
import static org.zalando.stups.tokens.util.Objects.notNull;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.zalando.stups.tokens.util.Objects;
/**
* Configuration for one single access token that is managed by the {@link AccessTokens} service.
* It is used at configuration time and is retrieved via
* {@link AccessTokensBuilder#manageToken(Object)}. It is possible to configure the desired
* <i>scopes</i> (see https://tools.ietf.org/html/rfc6749#section-3.3 for details) as well as the
* <i>grant type</i> (see https://tools.ietf.org/html/rfc6749#section-1.3 for details) for this
* access token. It follows a fluent interface design pattern.
*
* Invoke {@link AccessTokenConfiguration#done()} after you finished configuring this access token
* to return to the fluent interface of the {@link AccessTokensBuilder} to either add another
* managed access token or add additional configuration.
*
*/
public class AccessTokenConfiguration {
protected static final String DEFAULT_GRANT_TYPE = "password";
private final Object tokenId;
private final AccessTokensBuilder accessTokensBuilder;
private String grantType;
private final Set<Object> scopes = new HashSet<>();
private boolean locked = false;
AccessTokenConfiguration(final Object tokenId, final AccessTokensBuilder accessTokensBuilder) {
this(tokenId, accessTokensBuilder, DEFAULT_GRANT_TYPE);
}
AccessTokenConfiguration(final Object tokenId, final AccessTokensBuilder accessTokensBuilder,
final String grantType) {
this.tokenId = notNull("tokenId", tokenId);
this.accessTokensBuilder = notNull("accessTokenBuilder", accessTokensBuilder);
this.grantType = notBlank("grantType", notNull("grantType", grantType));
}
private void checkLock() {
if (locked) {
throw new IllegalStateException("scope configuration already done");
}
}
/**
* Add a single scope to this access token. Scopes will most of the time being expressed as
* plain strings. If the scope is not a {@link String} it {@link Object#toString()} method will
* be invoked when requesting the access token from the authorization server.
*
* @param scope The scope to add for this access token. An {@link IllegalArgumentException}
* will be thrown in case of <i>scope</i> being <i>null</i>.
* @return The same {@link AccessTokenConfiguration} instance this method has been called upon
* with the supplied <i>scope</i> added to the set of existing scopes.
*
* @deprecated Use {@link AccessTokenConfiguration#addScope(String)} instead and invoke
* {@link Object#toString()} before if necessary.
*/
@Deprecated
public AccessTokenConfiguration addScope(final Object scope) {
checkLock();
scopes.add(notNull("scope", scope));
return this;
}
/**
* Add a single scope to this access token.
*
* @param scope The scope to add for this access token. An {@link IllegalArgumentException}
* will be thrown in case of <i>scope</i> being <i>null</i> or <i>empty</i>.
* @return The same {@link AccessTokenConfiguration} instance this method has been called upon
* with the supplied <i>scope</i> added to the set of existing scopes.
*
*/
public AccessTokenConfiguration addScope(final String scope) {
checkLock();
scopes.add(notBlank("scope", scope));
return this;
}
/**
* Add multiple scopes to this access token. Refer to
* {@link AccessTokenConfiguration#addScope(Object)} for more detailed description of a scope.
*
* @param scopes A {@link Collection} of scopes that should be added to this access token. An
* {@link IllegalArgumentException} will be throws if either <i>scopes</i> being
* <i>null</i> or {@link Collection#contains(Object)} is <i>true</i> for the
* <i>null</i> arguments.
* Please note that scopes are stored as {@link Set} internally, i.e. duplicates
* with respect to {@link Object#hashCode()} and {@link Object#equals(Object)}
* will be removed.
* @return The same {@link AccessTokenConfiguration} instance this method has been called upon
* with the supplied <i>scopes</i> added to the set of existing scopes.
*
* @deprecated Use {@link AccessTokenConfiguration#addScopesTypeSafe(Collection)} instead and
* invoke {@link Object#toString()} on each element before if necessary
*/
@Deprecated
public AccessTokenConfiguration addScopes(final Collection<?> scopes) {
checkLock();
this.scopes.addAll(noNullEntries("scopes", scopes));
return this;
}
/**
* Add multiple scopes to this access token. Refer to
* {@link AccessTokenConfiguration#addScope(Object)} for more detailed description of a scope.
*
* @param scopes A {@link Collection} of scopes that should be added to this access token. An
* {@link IllegalArgumentException} will be throws if either <i>scopes</i> being
* <i>null</i> or {@link Collection#contains(Object)} is <i>true</i> for the
* <i>null</i> arguments.
* Please note that scopes are stored as {@link Set} internally, i.e. duplicates
* with respect to {@link Object#hashCode()} and {@link Object#equals(Object)}
* will be removed.
* @return The same {@link AccessTokenConfiguration} instance this method has been called upon
* with the supplied <i>scopes</i> added to the set of existing scopes.
*/
public AccessTokenConfiguration addScopesTypeSafe(final Collection<String> scopes) {
checkLock();
this.scopes.addAll(noBlankEntries("scopes", scopes));
return this;
}
/**
* Set the grant type to be used for this access token. For possible valid grant types see
* https://tools.ietf.org/html/rfc6749#section-1.3. Defaults to <i>password</i>.
*
* @param grantType The <i>grant type</i> to be used when requesting an access token.
* @return The same {@link AccessTokenConfiguration} instance this method has been called upon
* with the supplied <i>grant type</i> set.
*/
public AccessTokenConfiguration withGrantType(final String grantType) {
checkLock();
this.grantType = Objects.notBlank("grantType", notNull("grantType", grantType));
return this;
}
public Object getTokenId() {
return tokenId;
}
Set<Object> getScopes() {
return Collections.unmodifiableSet(scopes);
}
/**
* Finish configuring this access token, lock the configuration and return to the
* {@link AccessTokensBuilder} for further configuration of additional access tokens or other
* aspects.
*
* @return The {@link AccessTokensBuilder} that was used to create this
* {@link AccessTokenConfiguration} with an access token configured according to this instance.
*/
public AccessTokensBuilder done() {
locked = true;
return accessTokensBuilder;
}
/**
* Get the <i>grant type</i> for this access token.
*
* @return The grant type for this access token
*/
public String getGrantType() {
return grantType;
}
}