/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.keycloak.protocol.oidc.utils;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class OIDCResponseType {
public static final String CODE = OIDCLoginProtocol.CODE_PARAM;
public static final String TOKEN = "token";
public static final String ID_TOKEN = "id_token";
public static final String NONE = "none";
private static final List<String> ALLOWED_RESPONSE_TYPES = Arrays.asList(CODE, TOKEN, ID_TOKEN, NONE);
private final List<String> responseTypes;
private OIDCResponseType(List<String> responseTypes) {
this.responseTypes = responseTypes;
}
public static OIDCResponseType parse(String responseTypeParam) {
if (responseTypeParam == null) {
throw new IllegalArgumentException("response_type is null");
}
String[] responseTypes = responseTypeParam.trim().split(" ");
List<String> allowedTypes = new ArrayList<>();
for (String current : responseTypes) {
if (ALLOWED_RESPONSE_TYPES.contains(current)) {
allowedTypes.add(current);
} else {
throw new IllegalArgumentException("Unsupported response_type: " + responseTypeParam);
}
}
validateAllowedTypes(allowedTypes);
return new OIDCResponseType(allowedTypes);
}
public static OIDCResponseType parse(List<String> responseTypes) {
OIDCResponseType result = new OIDCResponseType(new ArrayList<String>());
for (String respType : responseTypes) {
OIDCResponseType responseType = parse(respType);
result.responseTypes.addAll(responseType.responseTypes);
}
return result;
}
private static void validateAllowedTypes(List<String> responseTypes) {
if (responseTypes.size() == 0) {
throw new IllegalStateException("No responseType provided");
}
if (responseTypes.contains(NONE) && responseTypes.size() > 1) {
throw new IllegalArgumentException("'None' not allowed with some other response_type");
}
// response_type value "token" alone is not mentioned in OIDC specification, however it is supported by OAuth2. We allow it just to be compatible with pure OAuth2 clients like swagger.ui
// if (responseTypes.contains(TOKEN) && responseTypes.size() == 1) {
// throw new IllegalArgumentException("Not supported to use response_type=token alone");
// }
}
public boolean hasResponseType(String responseType) {
return responseTypes.contains(responseType);
}
public boolean isImplicitOrHybridFlow() {
return hasResponseType(TOKEN) || hasResponseType(ID_TOKEN);
}
public boolean isImplicitFlow() {
return (hasResponseType(TOKEN) || hasResponseType(ID_TOKEN)) && !hasResponseType(CODE);
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
boolean first = true;
for (String responseType : responseTypes) {
if (!first) {
builder.append(" ");
} else {
first = false;
}
builder.append(responseType);
}
return builder.toString();
}
}