KEYCLOAK-19374 Create implementation based on annotation processor
Use of boxed types as started in 009d4ca445
is finalized here
to enable storing data in a map. MapClientEntity methods are
reordered for the sake of grouping the collection-based
properties together and understanding the connections between those.
This commit is contained in:
parent
12d4837fa9
commit
3abf9283a8
17 changed files with 728 additions and 752 deletions
27
model/build-processor/pom.xml
Normal file
27
model/build-processor/pom.xml
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>keycloak-model-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>16.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-model-build-processor</artifactId>
|
||||
<name>Keycloak Model Java Annotations and Processor</name>
|
||||
<description/>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-all</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright 2021 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.models.map.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface GenerateEntityImplementations {
|
||||
String inherits() default "";
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright 2021 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.models.map.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface GenerateEnumMapFieldType {
|
||||
Class<?> value() default Void.class;
|
||||
}
|
|
@ -0,0 +1,328 @@
|
|||
/*
|
||||
* Copyright 2021 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.models.map.processor;
|
||||
|
||||
import org.keycloak.models.map.annotations.GenerateEntityImplementations;
|
||||
import org.keycloak.models.map.annotations.GenerateEnumMapFieldType;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.Name;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.type.NoType;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.Types;
|
||||
import javax.tools.Diagnostic.Kind;
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
@SupportedAnnotationTypes("org.keycloak.models.map.annotations.GenerateEntityImplementations")
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_8)
|
||||
public class GenerateEntityImplementationsProcessor extends AbstractProcessor {
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
for (TypeElement annotation : annotations) {
|
||||
Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(annotation);
|
||||
annotatedElements.stream()
|
||||
.map(TypeElement.class::cast)
|
||||
.forEach(this::processTypeElement);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void processTypeElement(TypeElement e) {
|
||||
if (e.getKind() != ElementKind.INTERFACE) {
|
||||
processingEnv.getMessager().printMessage(Kind.ERROR, "Annotation @GenerateEntityImplementations is only applicable to interface", e);
|
||||
return;
|
||||
}
|
||||
|
||||
// Find all properties
|
||||
Map<String, HashSet<ExecutableElement>> methodsPerAttribute = e.getEnclosedElements().stream()
|
||||
.filter(ExecutableElement.class::isInstance)
|
||||
.map(ExecutableElement.class::cast)
|
||||
.filter(ee -> ! (ee.getReceiverType() instanceof NoType))
|
||||
.collect(Collectors.toMap(this::determineAttributeFromMethodName, v -> new HashSet(Arrays.asList(v)), (a,b) -> { a.addAll(b); return a; }));
|
||||
|
||||
// Merge plurals with singulars
|
||||
methodsPerAttribute.keySet().stream()
|
||||
.filter(key -> methodsPerAttribute.containsKey(key + "s"))
|
||||
.collect(Collectors.toSet())
|
||||
.forEach(key -> {
|
||||
HashSet<ExecutableElement> removed = methodsPerAttribute.remove(key);
|
||||
methodsPerAttribute.get(key + "s").addAll(removed);
|
||||
});
|
||||
|
||||
try {
|
||||
generateImpl(e, methodsPerAttribute);
|
||||
} catch (IOException ex) {
|
||||
processingEnv.getMessager().printMessage(Kind.ERROR, "Could not generate implementation for class", e);
|
||||
}
|
||||
|
||||
// methodsPerAttribute.entrySet().stream()
|
||||
// .sorted(Comparator.comparing(Map.Entry::getKey))
|
||||
// .forEach(me -> processingEnv.getMessager().printMessage(
|
||||
// Diagnostic.Kind.NOTE,
|
||||
// "** " + me.getKey() + ": " + me.getValue().stream().map(ExecutableElement::getSimpleName).sorted(Comparator.comparing(Object::toString)).collect(Collectors.joining(", ")))
|
||||
// );
|
||||
}
|
||||
|
||||
private static final Pattern BEAN_NAME = Pattern.compile("(get|set|is|delete|remove|add|update)([A-Z]\\S+)");
|
||||
private static final Map<String, String> FORBIDDEN_PREFIXES = new HashMap<>();
|
||||
static {
|
||||
FORBIDDEN_PREFIXES.put("delete", "remove");
|
||||
}
|
||||
|
||||
private String determineAttributeFromMethodName(ExecutableElement e) {
|
||||
Name name = e.getSimpleName();
|
||||
Matcher m = BEAN_NAME.matcher(name.toString());
|
||||
if (m.matches()) {
|
||||
String prefix = m.group(1);
|
||||
if (FORBIDDEN_PREFIXES.containsKey(prefix)) {
|
||||
processingEnv.getMessager().printMessage(
|
||||
Kind.ERROR,
|
||||
"Forbidden prefix " + prefix + "... detected, use " + FORBIDDEN_PREFIXES.get(prefix) + "... instead", e
|
||||
);
|
||||
}
|
||||
return m.group(2);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void generateImpl(TypeElement e, Map<String, HashSet<ExecutableElement>> methodsPerAttribute) throws IOException {
|
||||
GenerateEntityImplementations an = e.getAnnotation(GenerateEntityImplementations.class);
|
||||
Elements elements = processingEnv.getElementUtils();
|
||||
TypeElement parentTypeElement = elements.getTypeElement(an.inherits().isEmpty() ? "void" : an.inherits());
|
||||
final List<? extends Element> allMembers = elements.getAllMembers(parentTypeElement);
|
||||
String className = e.getQualifiedName().toString();
|
||||
String packageName = null;
|
||||
int lastDot = className.lastIndexOf('.');
|
||||
if (lastDot > 0) {
|
||||
packageName = className.substring(0, lastDot);
|
||||
}
|
||||
|
||||
String simpleClassName = className.substring(lastDot + 1);
|
||||
String mapImplClassName = className + "Impl";
|
||||
String mapSimpleClassName = simpleClassName + "Impl";
|
||||
|
||||
JavaFileObject enumFile = processingEnv.getFiler().createSourceFile(mapImplClassName);
|
||||
try (PrintWriter pw = new PrintWriter(enumFile.openWriter()) {
|
||||
@Override
|
||||
public void println(String x) {
|
||||
super.println(x == null ? x : x.replaceAll("java.lang.", ""));
|
||||
}
|
||||
}) {
|
||||
if (packageName != null) {
|
||||
pw.println("package " + packageName + ";");
|
||||
}
|
||||
|
||||
pw.println("import java.util.EnumMap;");
|
||||
pw.println("import java.util.Objects;");
|
||||
pw.println("// DO NOT CHANGE THIS CLASS, IT IS GENERATED AUTOMATICALLY BY " + GenerateEntityImplementationsProcessor.class.getSimpleName());
|
||||
pw.println("public class " + mapSimpleClassName + (an.inherits().isEmpty() ? "" : " extends " + an.inherits()) + " implements " + className + " {");
|
||||
pw.println(" public enum Field {");
|
||||
methodsPerAttribute.keySet().stream()
|
||||
.sorted()
|
||||
.map(GenerateEntityImplementationsProcessor::toEnumConstant)
|
||||
.forEach(key -> pw.println(" " + key + ","));
|
||||
pw.println(" }");
|
||||
pw.println(" private final EnumMap<Field, Object> values = new EnumMap<>(Field.class);");
|
||||
pw.println(" protected Object get(Field field) { return values.get(field); }");
|
||||
pw.println(" protected Object set(Field field, Object p0) { return values.put(field, p0); }");
|
||||
|
||||
// Constructors
|
||||
allMembers.stream()
|
||||
.filter(ExecutableElement.class::isInstance)
|
||||
.map(ExecutableElement.class::cast)
|
||||
.filter((ExecutableElement ee) -> ee.getKind() == ElementKind.CONSTRUCTOR)
|
||||
.forEach((ExecutableElement ee) -> pw.println(" public " + mapSimpleClassName + "(" + methodParameters(ee.getParameters()) + ") { super(" + ee.getParameters() + "); }"));
|
||||
|
||||
for (Entry<String, HashSet<ExecutableElement>> me : methodsPerAttribute.entrySet()) {
|
||||
String enumConstant = toEnumConstant(me.getKey());
|
||||
HashSet<ExecutableElement> methods = me.getValue();
|
||||
TypeMirror fieldType = determineFieldType(me.getKey(), methods);
|
||||
if (fieldType == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (ExecutableElement method : methods) {
|
||||
if (! printMethodBody(pw, method, me.getKey(), enumConstant, fieldType)) {
|
||||
List<ExecutableElement> parentMethods = allMembers.stream()
|
||||
.filter(ExecutableElement.class::isInstance)
|
||||
.map(ExecutableElement.class::cast)
|
||||
.filter(ee -> Objects.equals(ee.toString(), method.toString()))
|
||||
.filter((ExecutableElement ee) -> ! ee.getModifiers().contains(Modifier.ABSTRACT))
|
||||
.collect(Collectors.toList());
|
||||
if (! parentMethods.isEmpty()) {
|
||||
processingEnv.getMessager().printMessage(Kind.OTHER, "Method " + method + " is declared in a parent class.");
|
||||
} else {
|
||||
processingEnv.getMessager().printMessage(Kind.WARNING, "Could not determine desired semantics of method from its signature", method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pw.println("}");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected static String toEnumConstant(String key) {
|
||||
return key.replaceAll("([a-z])([A-Z])", "$1_$2").toUpperCase();
|
||||
}
|
||||
|
||||
private TypeMirror determineFieldType(String fieldName, HashSet<ExecutableElement> methods) {
|
||||
Pattern getter = Pattern.compile("(get|is)" + Pattern.quote(fieldName));
|
||||
TypeMirror res = null;
|
||||
for (ExecutableElement method : methods) {
|
||||
if (getter.matcher(method.getSimpleName()).matches() && method.getParameters().isEmpty()) {
|
||||
return method.getReturnType();
|
||||
}
|
||||
}
|
||||
if (res == null) {
|
||||
processingEnv.getMessager().printMessage(Kind.ERROR, "Could not determine return type for field " + fieldName, methods.iterator().next());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private boolean printMethodBody(PrintWriter pw, ExecutableElement method, String fieldName, String enumConstant, TypeMirror fieldType) {
|
||||
Pattern getter = Pattern.compile("(get|is)" + Pattern.quote(fieldName));
|
||||
Types types = processingEnv.getTypeUtils();
|
||||
final String methodName = method.getSimpleName().toString();
|
||||
String setter = "set" + fieldName;
|
||||
TypeMirror firstParameterType = method.getParameters().isEmpty()
|
||||
? types.getNullType()
|
||||
: method.getParameters().get(0).asType();
|
||||
String fieldNameSingular = fieldName.endsWith("s") ? fieldName.substring(0, fieldName.length() - 1) : fieldName;
|
||||
String getFromMap = "get" + fieldNameSingular;
|
||||
String addToCollection = "add" + fieldNameSingular;
|
||||
String updateMap = "set" + fieldNameSingular;
|
||||
String removeFromCollection = "remove" + fieldNameSingular;
|
||||
Elements elements = processingEnv.getElementUtils();
|
||||
TypeElement typeElement = elements.getTypeElement(types.erasure(fieldType).toString());
|
||||
|
||||
if (getter.matcher(methodName).matches() && method.getParameters().isEmpty() && types.isSameType(fieldType, method.getReturnType())) {
|
||||
pw.println(" @Override public " + method.getReturnType() + " " + method + " {");
|
||||
pw.println(" return (" + fieldType + ") get(Field." + enumConstant + ");");
|
||||
pw.println(" }");
|
||||
return true;
|
||||
} else if (setter.equals(methodName) && types.isSameType(firstParameterType, fieldType)) {
|
||||
pw.println(" @Override public " + method.getReturnType() + " " + method.getSimpleName() + "(" + firstParameterType + " p0) {");
|
||||
pw.println(" Object o = set(Field." + enumConstant + ", p0);");
|
||||
pw.println(" updated |= ! Objects.equals(o, p0);");
|
||||
pw.println(" }");
|
||||
return true;
|
||||
} else if (addToCollection.equals(methodName) && method.getParameters().size() == 1) {
|
||||
pw.println(" @Override public " + method.getReturnType() + " " + method.getSimpleName() + "(" + firstParameterType + " p0) {");
|
||||
pw.println(" " + fieldType + " o = (" + fieldType + ") get(Field." + enumConstant + ");");
|
||||
pw.println(" if (o == null) { o = " + interfaceToImplementation(typeElement) + "; set(Field." + enumConstant + ", o); }");
|
||||
if (isSetType(typeElement)) {
|
||||
pw.println(" updated |= o.add(p0);");
|
||||
} else {
|
||||
pw.println(" o.add(p0);");
|
||||
pw.println(" updated = true;");
|
||||
}
|
||||
pw.println(" }");
|
||||
return true;
|
||||
} else if (removeFromCollection.equals(methodName) && method.getParameters().size() == 1) {
|
||||
pw.println(" @Override public " + method.getReturnType() + " " + method.getSimpleName() + "(" + firstParameterType + " p0) {");
|
||||
pw.println(" " + fieldType + " o = (" + fieldType + ") get(Field." + enumConstant + ");");
|
||||
pw.println(" if (o == null) { return; }");
|
||||
pw.println(" boolean removed = o.remove(p0)" + ("java.util.Map".equals(typeElement.getQualifiedName().toString()) ? " != null" : "") + ";");
|
||||
pw.println(" updated |= removed;");
|
||||
pw.println(" }");
|
||||
return true;
|
||||
} else if (updateMap.equals(methodName) && method.getParameters().size() == 2) {
|
||||
pw.println(" @Override public " + method.getReturnType() + " " + method.getSimpleName() + "(" + firstParameterType + " p0, " + method.getParameters().get(1).asType() + " p1) {");
|
||||
pw.println(" " + fieldType + " o = (" + fieldType + ") get(Field." + enumConstant + ");");
|
||||
pw.println(" if (o == null) { o = " + interfaceToImplementation(typeElement) + "; set(Field." + enumConstant + ", o); }");
|
||||
pw.println(" Object v = o.put(p0, p1);");
|
||||
pw.println(" updated |= ! Objects.equals(v, p1);");
|
||||
pw.println(" }");
|
||||
return true;
|
||||
} else if (getFromMap.equals(methodName) && method.getParameters().size() == 1) {
|
||||
pw.println(" @Override public " + method.getReturnType() + " " + method.getSimpleName() + "(" + firstParameterType + " p0) {");
|
||||
pw.println(" " + fieldType + " o = (" + fieldType + ") get(Field." + enumConstant + ");");
|
||||
pw.println(" return o == null ? null : o.get(p0);");
|
||||
pw.println(" }");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private String interfaceToImplementation(TypeElement typeElement) {
|
||||
GenerateEnumMapFieldType an = typeElement.getAnnotation(GenerateEnumMapFieldType.class);
|
||||
if (an != null) {
|
||||
return "new " + an.value().getCanonicalName() + "<>()";
|
||||
}
|
||||
|
||||
Name parameterTypeQN = typeElement.getQualifiedName();
|
||||
switch (parameterTypeQN.toString()) {
|
||||
case "java.util.List":
|
||||
return "new java.util.LinkedList<>()";
|
||||
case "java.util.Map":
|
||||
return "new java.util.HashMap<>()";
|
||||
case "java.util.Set":
|
||||
return "new java.util.HashSet<>()";
|
||||
case "java.util.Collection":
|
||||
return "new java.util.LinkedList<>()";
|
||||
default:
|
||||
processingEnv.getMessager().printMessage(Kind.ERROR, "Could not determine implementation for type " + typeElement, typeElement);
|
||||
return "TODO()";
|
||||
}
|
||||
}
|
||||
|
||||
private String methodParameters(List<? extends VariableElement> parameters) {
|
||||
return parameters.stream()
|
||||
.map(p -> p.asType() + " " + p.getSimpleName())
|
||||
.collect(Collectors.joining(", "));
|
||||
}
|
||||
|
||||
private static final HashSet<String> SET_TYPES = new HashSet<>(Arrays.asList(Set.class.getCanonicalName(), TreeSet.class.getCanonicalName(), HashSet.class.getCanonicalName(), LinkedHashSet.class.getCanonicalName()));
|
||||
|
||||
private boolean isSetType(TypeElement typeElement) {
|
||||
Name name = typeElement.getQualifiedName();
|
||||
return SET_TYPES.contains(name.toString());
|
||||
}
|
||||
}
|
|
@ -11,6 +11,27 @@
|
|||
<name>Keycloak Model Map</name>
|
||||
<description/>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-build-processor</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
<annotationProcessors>
|
||||
<annotationProcessor>org.keycloak.models.map.processor.GenerateEntityImplementationsProcessor</annotationProcessor>
|
||||
</annotationProcessors>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
|
@ -42,6 +63,13 @@
|
|||
<artifactId>hamcrest-all</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-build-processor</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
|
@ -23,6 +23,7 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -79,7 +80,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return entity.isEnabled();
|
||||
final Boolean enabled = entity.isEnabled();
|
||||
return enabled == null ? false : enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -89,7 +91,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
|
||||
@Override
|
||||
public boolean isAlwaysDisplayInConsole() {
|
||||
return entity.isAlwaysDisplayInConsole();
|
||||
final Boolean alwaysDisplayInConsole = entity.isAlwaysDisplayInConsole();
|
||||
return alwaysDisplayInConsole == null ? false : alwaysDisplayInConsole;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -99,7 +102,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
|
||||
@Override
|
||||
public boolean isSurrogateAuthRequired() {
|
||||
return entity.isSurrogateAuthRequired();
|
||||
final Boolean surrogateAuthRequired = entity.isSurrogateAuthRequired();
|
||||
return surrogateAuthRequired == null ? false : surrogateAuthRequired;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -109,7 +113,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
|
||||
@Override
|
||||
public Set<String> getWebOrigins() {
|
||||
return entity.getWebOrigins();
|
||||
final Set<String> webOrigins = entity.getWebOrigins();
|
||||
return webOrigins == null ? Collections.emptySet() : webOrigins;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -129,7 +134,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
|
||||
@Override
|
||||
public Set<String> getRedirectUris() {
|
||||
return entity.getRedirectUris();
|
||||
final Set<String> redirectUris = entity.getRedirectUris();
|
||||
return redirectUris == null ? Collections.emptySet() : redirectUris;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -179,7 +185,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
|
||||
@Override
|
||||
public boolean isBearerOnly() {
|
||||
return entity.isBearerOnly();
|
||||
final Boolean bearerOnly = entity.isBearerOnly();
|
||||
return bearerOnly == null ? false : bearerOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -214,7 +221,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
|
||||
@Override
|
||||
public int getNodeReRegistrationTimeout() {
|
||||
return entity.getNodeReRegistrationTimeout();
|
||||
final Integer nodeReRegistrationTimeout = entity.getNodeReRegistrationTimeout();
|
||||
return nodeReRegistrationTimeout == null ? 0 : nodeReRegistrationTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -265,13 +273,15 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
@Override
|
||||
public String getAttribute(String name) {
|
||||
List<String> attribute = entity.getAttribute(name);
|
||||
if (attribute.isEmpty()) return null;
|
||||
if (attribute == null || attribute.isEmpty()) return null;
|
||||
return attribute.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAttributes() {
|
||||
return entity.getAttributes().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,
|
||||
final Map<String, List<String>> attributes = entity.getAttributes();
|
||||
final Map<String, List<String>> a = attributes == null ? Collections.emptyMap() : attributes;
|
||||
return a.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,
|
||||
entry -> {
|
||||
if (entry.getValue().isEmpty()) return null;
|
||||
return entry.getValue().get(0);
|
||||
|
@ -286,7 +296,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
|
||||
@Override
|
||||
public Map<String, String> getAuthenticationFlowBindingOverrides() {
|
||||
return entity.getAuthenticationFlowBindingOverrides();
|
||||
final Map<String, String> authenticationFlowBindingOverrides = entity.getAuthenticationFlowBindingOverrides();
|
||||
return authenticationFlowBindingOverrides == null ? Collections.emptyMap() : authenticationFlowBindingOverrides;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -301,7 +312,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
|
||||
@Override
|
||||
public boolean isFrontchannelLogout() {
|
||||
return entity.isFrontchannelLogout();
|
||||
final Boolean frontchannelLogout = entity.isFrontchannelLogout();
|
||||
return frontchannelLogout == null ? false : frontchannelLogout;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -311,7 +323,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
|
||||
@Override
|
||||
public boolean isFullScopeAllowed() {
|
||||
return entity.isFullScopeAllowed();
|
||||
final Boolean fullScopeAllowed = entity.isFullScopeAllowed();
|
||||
return fullScopeAllowed == null ? false : fullScopeAllowed;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -321,7 +334,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
|
||||
@Override
|
||||
public boolean isPublicClient() {
|
||||
return entity.isPublicClient();
|
||||
final Boolean publicClient = entity.isPublicClient();
|
||||
return publicClient == null ? false : publicClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -331,7 +345,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
|
||||
@Override
|
||||
public boolean isConsentRequired() {
|
||||
return entity.isConsentRequired();
|
||||
final Boolean consentRequired = entity.isConsentRequired();
|
||||
return consentRequired == null ? false : consentRequired;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -341,7 +356,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
|
||||
@Override
|
||||
public boolean isStandardFlowEnabled() {
|
||||
return entity.isStandardFlowEnabled();
|
||||
final Boolean standardFlowEnabled = entity.isStandardFlowEnabled();
|
||||
return standardFlowEnabled == null ? false : standardFlowEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -351,7 +367,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
|
||||
@Override
|
||||
public boolean isImplicitFlowEnabled() {
|
||||
return entity.isImplicitFlowEnabled();
|
||||
final Boolean implicitFlowEnabled = entity.isImplicitFlowEnabled();
|
||||
return implicitFlowEnabled == null ? false : implicitFlowEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -361,7 +378,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
|
||||
@Override
|
||||
public boolean isDirectAccessGrantsEnabled() {
|
||||
return entity.isDirectAccessGrantsEnabled();
|
||||
final Boolean directAccessGrantsEnabled = entity.isDirectAccessGrantsEnabled();
|
||||
return directAccessGrantsEnabled == null ? false : directAccessGrantsEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -371,7 +389,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
|
||||
@Override
|
||||
public boolean isServiceAccountsEnabled() {
|
||||
return entity.isServiceAccountsEnabled();
|
||||
final Boolean serviceAccountsEnabled = entity.isServiceAccountsEnabled();
|
||||
return serviceAccountsEnabled == null ? false : serviceAccountsEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -386,7 +405,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
|
||||
@Override
|
||||
public int getNotBefore() {
|
||||
return entity.getNotBefore();
|
||||
final Integer notBefore = entity.getNotBefore();
|
||||
return notBefore == null ? 0 : notBefore;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -398,7 +418,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
|
||||
@Override
|
||||
public Stream<RoleModel> getScopeMappingsStream() {
|
||||
return this.entity.getScopeMappings().stream()
|
||||
final Collection<String> scopeMappings = this.entity.getScopeMappings();
|
||||
return scopeMappings == null ? Stream.empty() : scopeMappings.stream()
|
||||
.map(realm::getRoleById)
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
@ -415,7 +436,7 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
public void deleteScopeMapping(RoleModel role) {
|
||||
final String id = role == null ? null : role.getId();
|
||||
if (id != null) {
|
||||
this.entity.deleteScopeMapping(id);
|
||||
this.entity.removeScopeMapping(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -434,7 +455,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
if (isFullScopeAllowed()) return true;
|
||||
|
||||
final String id = role == null ? null : role.getId();
|
||||
if (id != null && this.entity.getScopeMappings().contains(id)) {
|
||||
final Collection<String> scopeMappings = this.entity.getScopeMappings();
|
||||
if (id != null && scopeMappings != null && scopeMappings.contains(id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -483,7 +505,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
|
||||
@Override
|
||||
public Stream<ProtocolMapperModel> getProtocolMappersStream() {
|
||||
return entity.getProtocolMappers().stream().distinct();
|
||||
final Map<String, ProtocolMapperModel> protocolMappers = entity.getProtocolMappers();
|
||||
return protocolMappers == null ? Stream.empty() : protocolMappers.values().stream().distinct();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -504,7 +527,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
pm.setConfig(new HashMap<>());
|
||||
}
|
||||
|
||||
return entity.addProtocolMapper(pm);
|
||||
entity.setProtocolMapper(pm.getId(), pm);
|
||||
return pm;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -519,18 +543,19 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
|||
public void updateProtocolMapper(ProtocolMapperModel mapping) {
|
||||
final String id = mapping == null ? null : mapping.getId();
|
||||
if (id != null) {
|
||||
entity.updateProtocolMapper(id, mapping);
|
||||
entity.setProtocolMapper(id, mapping);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolMapperModel getProtocolMapperById(String id) {
|
||||
return entity.getProtocolMapperById(id);
|
||||
return entity.getProtocolMapper(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolMapperModel getProtocolMapperByName(String protocol, String name) {
|
||||
return entity.getProtocolMappers().stream()
|
||||
final Map<String, ProtocolMapperModel> protocolMappers = entity.getProtocolMappers();
|
||||
return protocolMappers == null ? null : protocolMappers.values().stream()
|
||||
.filter(pm -> Objects.equals(pm.getProtocol(), protocol) && Objects.equals(pm.getName(), name))
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
|
|
|
@ -22,36 +22,89 @@ import org.keycloak.models.map.common.UpdatableEntity;
|
|||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
import org.keycloak.models.map.annotations.GenerateEntityImplementations;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
@GenerateEntityImplementations(inherits="org.keycloak.models.map.client.MapClientEntity.AbstractClientEntity")
|
||||
public interface MapClientEntity extends AbstractEntity, UpdatableEntity {
|
||||
|
||||
void addClientScope(String id, Boolean defaultScope);
|
||||
static abstract class AbstractClientEntity implements MapClientEntity {
|
||||
/**
|
||||
* Flag signalizing that any of the setters has been meaningfully used.
|
||||
*/
|
||||
protected boolean updated;
|
||||
private String id;
|
||||
|
||||
ProtocolMapperModel addProtocolMapper(ProtocolMapperModel model);
|
||||
protected AbstractClientEntity() {
|
||||
this.id = null;
|
||||
}
|
||||
|
||||
public AbstractClientEntity(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUpdated() {
|
||||
return this.updated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> getClientScopes(boolean defaultScope) {
|
||||
final Map<String, Boolean> clientScopes = getClientScopes();
|
||||
return clientScopes == null ? Stream.empty() : clientScopes.entrySet().stream()
|
||||
.filter(me -> Objects.equals(me.getValue(), defaultScope))
|
||||
.map(Entry::getKey);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Boolean> getClientScopes();
|
||||
Stream<String> getClientScopes(boolean defaultScope);
|
||||
void setClientScope(String id, Boolean defaultScope);
|
||||
void removeClientScope(String id);
|
||||
|
||||
ProtocolMapperModel getProtocolMapper(String id);
|
||||
Map<String, ProtocolMapperModel> getProtocolMappers();
|
||||
void setProtocolMapper(String id, ProtocolMapperModel mapping);
|
||||
void removeProtocolMapper(String id);
|
||||
|
||||
void addRedirectUri(String redirectUri);
|
||||
Set<String> getRedirectUris();
|
||||
void removeRedirectUri(String redirectUri);
|
||||
void setRedirectUris(Set<String> redirectUris);
|
||||
|
||||
void addScopeMapping(String id);
|
||||
void removeScopeMapping(String id);
|
||||
Collection<String> getScopeMappings();
|
||||
|
||||
void addWebOrigin(String webOrigin);
|
||||
Set<String> getWebOrigins();
|
||||
void removeWebOrigin(String webOrigin);
|
||||
void setWebOrigins(Set<String> webOrigins);
|
||||
|
||||
void deleteScopeMapping(String id);
|
||||
|
||||
List<String> getAttribute(String name);
|
||||
|
||||
default List<String> getAttribute(String name) { return getAttributes().get(name); }
|
||||
Map<String, List<String>> getAttributes();
|
||||
void removeAttribute(String name);
|
||||
void setAttribute(String name, List<String> values);
|
||||
|
||||
Map<String, String> getAuthFlowBindings();
|
||||
void setAuthFlowBindings(Map<String, String> authFlowBindings);
|
||||
|
||||
String getAuthenticationFlowBindingOverride(String binding);
|
||||
|
||||
Map<String, String> getAuthenticationFlowBindingOverrides();
|
||||
void removeAuthenticationFlowBindingOverride(String binding);
|
||||
void setAuthenticationFlowBindingOverride(String binding, String flowId);
|
||||
|
||||
String getBaseUrl();
|
||||
|
||||
|
@ -59,40 +112,28 @@ public interface MapClientEntity extends AbstractEntity, UpdatableEntity {
|
|||
|
||||
String getClientId();
|
||||
|
||||
Stream<String> getClientScopes(boolean defaultScope);
|
||||
|
||||
String getDescription();
|
||||
|
||||
String getManagementUrl();
|
||||
|
||||
String getName();
|
||||
|
||||
int getNodeReRegistrationTimeout();
|
||||
Integer getNodeReRegistrationTimeout();
|
||||
|
||||
int getNotBefore();
|
||||
Integer getNotBefore();
|
||||
|
||||
String getProtocol();
|
||||
|
||||
ProtocolMapperModel getProtocolMapperById(String id);
|
||||
|
||||
Collection<ProtocolMapperModel> getProtocolMappers();
|
||||
|
||||
String getRealmId();
|
||||
|
||||
Set<String> getRedirectUris();
|
||||
|
||||
String getRegistrationToken();
|
||||
|
||||
String getRootUrl();
|
||||
|
||||
Set<String> getScope();
|
||||
|
||||
Collection<String> getScopeMappings();
|
||||
|
||||
String getSecret();
|
||||
|
||||
Set<String> getWebOrigins();
|
||||
|
||||
Boolean isAlwaysDisplayInConsole();
|
||||
|
||||
Boolean isBearerOnly();
|
||||
|
@ -117,26 +158,8 @@ public interface MapClientEntity extends AbstractEntity, UpdatableEntity {
|
|||
|
||||
Boolean isSurrogateAuthRequired();
|
||||
|
||||
void removeAttribute(String name);
|
||||
|
||||
void removeAuthenticationFlowBindingOverride(String binding);
|
||||
|
||||
void removeClientScope(String id);
|
||||
|
||||
void removeProtocolMapper(String id);
|
||||
|
||||
void removeRedirectUri(String redirectUri);
|
||||
|
||||
void removeWebOrigin(String webOrigin);
|
||||
|
||||
void setAlwaysDisplayInConsole(Boolean alwaysDisplayInConsole);
|
||||
|
||||
void setAttribute(String name, List<String> values);
|
||||
|
||||
void setAuthFlowBindings(Map<String, String> authFlowBindings);
|
||||
|
||||
void setAuthenticationFlowBindingOverride(String binding, String flowId);
|
||||
|
||||
void setBaseUrl(String baseUrl);
|
||||
|
||||
void setBearerOnly(Boolean bearerOnly);
|
||||
|
@ -163,17 +186,15 @@ public interface MapClientEntity extends AbstractEntity, UpdatableEntity {
|
|||
|
||||
void setName(String name);
|
||||
|
||||
void setNodeReRegistrationTimeout(int nodeReRegistrationTimeout);
|
||||
void setNodeReRegistrationTimeout(Integer nodeReRegistrationTimeout);
|
||||
|
||||
void setNotBefore(int notBefore);
|
||||
void setNotBefore(Integer notBefore);
|
||||
|
||||
void setProtocol(String protocol);
|
||||
|
||||
void setProtocolMappers(Collection<ProtocolMapperModel> protocolMappers);
|
||||
|
||||
void setPublicClient(Boolean publicClient);
|
||||
|
||||
void setRedirectUris(Set<String> redirectUris);
|
||||
void setRealmId(String realmId);
|
||||
|
||||
void setRegistrationToken(String registrationToken);
|
||||
|
||||
|
@ -189,8 +210,4 @@ public interface MapClientEntity extends AbstractEntity, UpdatableEntity {
|
|||
|
||||
void setSurrogateAuthRequired(Boolean surrogateAuthRequired);
|
||||
|
||||
void setWebOrigins(Set<String> webOrigins);
|
||||
|
||||
void updateProtocolMapper(String id, ProtocolMapperModel mapping);
|
||||
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ public class MapClientEntityDelegate extends MapClientEntityLazyDelegate {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected MapClientEntity getDelegate() {
|
||||
protected MapClientEntity getWriteDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,557 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 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.models.map.client;
|
||||
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class MapClientEntityImpl implements MapClientEntity {
|
||||
|
||||
private String id;
|
||||
private String realmId;
|
||||
|
||||
private String clientId;
|
||||
private String name;
|
||||
private String description;
|
||||
private Set<String> redirectUris = new HashSet<>();
|
||||
private boolean enabled;
|
||||
private boolean alwaysDisplayInConsole;
|
||||
private String clientAuthenticatorType;
|
||||
private String secret;
|
||||
private String registrationToken;
|
||||
private String protocol;
|
||||
private Map<String, List<String>> attributes = new HashMap<>();
|
||||
private Map<String, String> authFlowBindings = new HashMap<>();
|
||||
private boolean publicClient;
|
||||
private boolean fullScopeAllowed;
|
||||
private boolean frontchannelLogout;
|
||||
private int notBefore;
|
||||
private Set<String> scope = new HashSet<>();
|
||||
private Set<String> webOrigins = new HashSet<>();
|
||||
private Map<String, ProtocolMapperModel> protocolMappers = new HashMap<>();
|
||||
private Map<String, Boolean> clientScopes = new HashMap<>();
|
||||
private Set<String> scopeMappings = new LinkedHashSet<>();
|
||||
private boolean surrogateAuthRequired;
|
||||
private String managementUrl;
|
||||
private String rootUrl;
|
||||
private String baseUrl;
|
||||
private boolean bearerOnly;
|
||||
private boolean consentRequired;
|
||||
private boolean standardFlowEnabled;
|
||||
private boolean implicitFlowEnabled;
|
||||
private boolean directAccessGrantsEnabled;
|
||||
private boolean serviceAccountsEnabled;
|
||||
private int nodeReRegistrationTimeout;
|
||||
|
||||
/**
|
||||
* Flag signalizing that any of the setters has been meaningfully used.
|
||||
*/
|
||||
protected boolean updated;
|
||||
|
||||
protected MapClientEntityImpl() {
|
||||
this.id = null;
|
||||
this.realmId = null;
|
||||
}
|
||||
|
||||
public MapClientEntityImpl(String id, String realmId) {
|
||||
Objects.requireNonNull(realmId, "realmId");
|
||||
|
||||
this.id = id;
|
||||
this.realmId = realmId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUpdated() {
|
||||
return this.updated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientId(String clientId) {
|
||||
this.updated |= ! Objects.equals(this.clientId, clientId);
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
this.updated |= ! Objects.equals(this.name, name);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDescription(String description) {
|
||||
this.updated |= ! Objects.equals(this.description, description);
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getRedirectUris() {
|
||||
return redirectUris;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRedirectUris(Set<String> redirectUris) {
|
||||
this.updated |= ! Objects.equals(this.redirectUris, redirectUris);
|
||||
this.redirectUris = redirectUris;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(Boolean enabled) {
|
||||
this.updated |= ! Objects.equals(this.enabled, enabled);
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isAlwaysDisplayInConsole() {
|
||||
return alwaysDisplayInConsole;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlwaysDisplayInConsole(Boolean alwaysDisplayInConsole) {
|
||||
this.updated |= ! Objects.equals(this.alwaysDisplayInConsole, alwaysDisplayInConsole);
|
||||
this.alwaysDisplayInConsole = alwaysDisplayInConsole;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientAuthenticatorType() {
|
||||
return clientAuthenticatorType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientAuthenticatorType(String clientAuthenticatorType) {
|
||||
this.updated |= ! Objects.equals(this.clientAuthenticatorType, clientAuthenticatorType);
|
||||
this.clientAuthenticatorType = clientAuthenticatorType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSecret() {
|
||||
return secret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSecret(String secret) {
|
||||
this.updated |= ! Objects.equals(this.secret, secret);
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRegistrationToken() {
|
||||
return registrationToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRegistrationToken(String registrationToken) {
|
||||
this.updated |= ! Objects.equals(this.registrationToken, registrationToken);
|
||||
this.registrationToken = registrationToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProtocol(String protocol) {
|
||||
this.updated |= ! Objects.equals(this.protocol, protocol);
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, List<String> values) {
|
||||
this.updated |= ! Objects.equals(this.attributes.put(name, values), values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAuthFlowBindings() {
|
||||
return authFlowBindings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthFlowBindings(Map<String, String> authFlowBindings) {
|
||||
this.updated |= ! Objects.equals(this.authFlowBindings, authFlowBindings);
|
||||
this.authFlowBindings = authFlowBindings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isPublicClient() {
|
||||
return publicClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPublicClient(Boolean publicClient) {
|
||||
this.updated |= ! Objects.equals(this.publicClient, publicClient);
|
||||
this.publicClient = publicClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isFullScopeAllowed() {
|
||||
return fullScopeAllowed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFullScopeAllowed(Boolean fullScopeAllowed) {
|
||||
this.updated |= ! Objects.equals(this.fullScopeAllowed, fullScopeAllowed);
|
||||
this.fullScopeAllowed = fullScopeAllowed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isFrontchannelLogout() {
|
||||
return frontchannelLogout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFrontchannelLogout(Boolean frontchannelLogout) {
|
||||
this.updated |= ! Objects.equals(this.frontchannelLogout, frontchannelLogout);
|
||||
this.frontchannelLogout = frontchannelLogout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNotBefore() {
|
||||
return notBefore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNotBefore(int notBefore) {
|
||||
this.updated |= ! Objects.equals(this.notBefore, notBefore);
|
||||
this.notBefore = notBefore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScope(Set<String> scope) {
|
||||
this.updated |= ! Objects.equals(this.scope, scope);
|
||||
this.scope.clear();
|
||||
this.scope.addAll(scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getWebOrigins() {
|
||||
return webOrigins;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWebOrigins(Set<String> webOrigins) {
|
||||
this.updated |= ! Objects.equals(this.webOrigins, webOrigins);
|
||||
this.webOrigins.clear();
|
||||
this.webOrigins.addAll(webOrigins);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolMapperModel addProtocolMapper(ProtocolMapperModel model) {
|
||||
Objects.requireNonNull(model.getId(), "protocolMapper.id");
|
||||
updated = true;
|
||||
this.protocolMappers.put(model.getId(), model);
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ProtocolMapperModel> getProtocolMappers() {
|
||||
return protocolMappers.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProtocolMapper(String id, ProtocolMapperModel mapping) {
|
||||
updated = true;
|
||||
protocolMappers.put(id, mapping);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeProtocolMapper(String id) {
|
||||
updated |= protocolMappers.remove(id) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProtocolMappers(Collection<ProtocolMapperModel> protocolMappers) {
|
||||
this.updated |= ! Objects.equals(this.protocolMappers, protocolMappers);
|
||||
this.protocolMappers.clear();
|
||||
this.protocolMappers.putAll(protocolMappers.stream().collect(Collectors.toMap(ProtocolMapperModel::getId, Function.identity())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolMapperModel getProtocolMapperById(String id) {
|
||||
return id == null ? null : protocolMappers.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isSurrogateAuthRequired() {
|
||||
return surrogateAuthRequired;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSurrogateAuthRequired(Boolean surrogateAuthRequired) {
|
||||
this.updated |= ! Objects.equals(this.surrogateAuthRequired, surrogateAuthRequired);
|
||||
this.surrogateAuthRequired = surrogateAuthRequired;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getManagementUrl() {
|
||||
return managementUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setManagementUrl(String managementUrl) {
|
||||
this.updated |= ! Objects.equals(this.managementUrl, managementUrl);
|
||||
this.managementUrl = managementUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRootUrl() {
|
||||
return rootUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRootUrl(String rootUrl) {
|
||||
this.updated |= ! Objects.equals(this.rootUrl, rootUrl);
|
||||
this.rootUrl = rootUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBaseUrl() {
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBaseUrl(String baseUrl) {
|
||||
this.updated |= ! Objects.equals(this.baseUrl, baseUrl);
|
||||
this.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isBearerOnly() {
|
||||
return bearerOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBearerOnly(Boolean bearerOnly) {
|
||||
this.updated |= ! Objects.equals(this.bearerOnly, bearerOnly);
|
||||
this.bearerOnly = bearerOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isConsentRequired() {
|
||||
return consentRequired;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConsentRequired(Boolean consentRequired) {
|
||||
this.updated |= ! Objects.equals(this.consentRequired, consentRequired);
|
||||
this.consentRequired = consentRequired;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isStandardFlowEnabled() {
|
||||
return standardFlowEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStandardFlowEnabled(Boolean standardFlowEnabled) {
|
||||
this.updated |= ! Objects.equals(this.standardFlowEnabled, standardFlowEnabled);
|
||||
this.standardFlowEnabled = standardFlowEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isImplicitFlowEnabled() {
|
||||
return implicitFlowEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImplicitFlowEnabled(Boolean implicitFlowEnabled) {
|
||||
this.updated |= ! Objects.equals(this.implicitFlowEnabled, implicitFlowEnabled);
|
||||
this.implicitFlowEnabled = implicitFlowEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isDirectAccessGrantsEnabled() {
|
||||
return directAccessGrantsEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDirectAccessGrantsEnabled(Boolean directAccessGrantsEnabled) {
|
||||
this.updated |= ! Objects.equals(this.directAccessGrantsEnabled, directAccessGrantsEnabled);
|
||||
this.directAccessGrantsEnabled = directAccessGrantsEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isServiceAccountsEnabled() {
|
||||
return serviceAccountsEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setServiceAccountsEnabled(Boolean serviceAccountsEnabled) {
|
||||
this.updated |= ! Objects.equals(this.serviceAccountsEnabled, serviceAccountsEnabled);
|
||||
this.serviceAccountsEnabled = serviceAccountsEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNodeReRegistrationTimeout() {
|
||||
return nodeReRegistrationTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNodeReRegistrationTimeout(int nodeReRegistrationTimeout) {
|
||||
this.updated |= ! Objects.equals(this.nodeReRegistrationTimeout, nodeReRegistrationTimeout);
|
||||
this.nodeReRegistrationTimeout = nodeReRegistrationTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addWebOrigin(String webOrigin) {
|
||||
updated = true;
|
||||
this.webOrigins.add(webOrigin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeWebOrigin(String webOrigin) {
|
||||
updated |= this.webOrigins.remove(webOrigin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRedirectUri(String redirectUri) {
|
||||
this.updated |= ! this.redirectUris.contains(redirectUri);
|
||||
this.redirectUris.add(redirectUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRedirectUri(String redirectUri) {
|
||||
updated |= this.redirectUris.remove(redirectUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String name) {
|
||||
this.updated |= this.attributes.remove(name) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAttribute(String name) {
|
||||
return attributes.getOrDefault(name, Collections.EMPTY_LIST);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthenticationFlowBindingOverride(String binding) {
|
||||
return this.authFlowBindings.get(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAuthenticationFlowBindingOverrides() {
|
||||
return this.authFlowBindings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAuthenticationFlowBindingOverride(String binding) {
|
||||
updated |= this.authFlowBindings.remove(binding) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthenticationFlowBindingOverride(String binding, String flowId) {
|
||||
this.updated = true;
|
||||
this.authFlowBindings.put(binding, flowId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getScopeMappings() {
|
||||
return scopeMappings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addScopeMapping(String id) {
|
||||
if (id != null) {
|
||||
updated = true;
|
||||
scopeMappings.add(id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteScopeMapping(String id) {
|
||||
updated |= scopeMappings.remove(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addClientScope(String id, Boolean defaultScope) {
|
||||
if (id != null) {
|
||||
updated = true;
|
||||
this.clientScopes.put(id, defaultScope);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeClientScope(String id) {
|
||||
if (id != null) {
|
||||
updated |= clientScopes.remove(id) != null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> getClientScopes(boolean defaultScope) {
|
||||
return this.clientScopes.entrySet().stream()
|
||||
.filter(me -> Objects.equals(me.getValue(), defaultScope))
|
||||
.map(Entry::getKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRealmId() {
|
||||
return this.realmId;
|
||||
}
|
||||
|
||||
}
|
|
@ -39,8 +39,8 @@ public class MapClientEntityLazyDelegate implements MapClientEntity {
|
|||
this.delegateSupplier = delegateSupplier;
|
||||
}
|
||||
|
||||
protected MapClientEntity getDelegate() {
|
||||
if (! delegate.isMarked()) {
|
||||
protected MapClientEntity getWriteDelegate() {
|
||||
if (! isWriteDelegateInitialized()) {
|
||||
delegate.compareAndSet(null, delegateSupplier == null ? null : delegateSupplier.get(), false, true);
|
||||
}
|
||||
MapClientEntity ref = delegate.getReference();
|
||||
|
@ -50,419 +50,427 @@ public class MapClientEntityLazyDelegate implements MapClientEntity {
|
|||
return ref;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addClientScope(String id, Boolean defaultScope) {
|
||||
getDelegate().addClientScope(id, defaultScope);
|
||||
protected boolean isWriteDelegateInitialized() {
|
||||
return delegate.isMarked();
|
||||
}
|
||||
|
||||
protected MapClientEntity getReadDelegate() {
|
||||
return getWriteDelegate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolMapperModel addProtocolMapper(ProtocolMapperModel model) {
|
||||
return getDelegate().addProtocolMapper(model);
|
||||
public void setClientScope(String id, Boolean defaultScope) {
|
||||
getWriteDelegate().setClientScope(id, defaultScope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRedirectUri(String redirectUri) {
|
||||
getDelegate().addRedirectUri(redirectUri);
|
||||
getWriteDelegate().addRedirectUri(redirectUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addScopeMapping(String id) {
|
||||
getDelegate().addScopeMapping(id);
|
||||
getWriteDelegate().addScopeMapping(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addWebOrigin(String webOrigin) {
|
||||
getDelegate().addWebOrigin(webOrigin);
|
||||
getWriteDelegate().addWebOrigin(webOrigin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteScopeMapping(String id) {
|
||||
getDelegate().deleteScopeMapping(id);
|
||||
public void removeScopeMapping(String id) {
|
||||
getWriteDelegate().removeScopeMapping(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAttribute(String name) {
|
||||
return getDelegate().getAttribute(name);
|
||||
return getReadDelegate().getAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getAttributes() {
|
||||
return getDelegate().getAttributes();
|
||||
return getReadDelegate().getAttributes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAuthFlowBindings() {
|
||||
return getDelegate().getAuthFlowBindings();
|
||||
return getReadDelegate().getAuthFlowBindings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthenticationFlowBindingOverride(String binding) {
|
||||
return getDelegate().getAuthenticationFlowBindingOverride(binding);
|
||||
return getReadDelegate().getAuthenticationFlowBindingOverride(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAuthenticationFlowBindingOverrides() {
|
||||
return getDelegate().getAuthenticationFlowBindingOverrides();
|
||||
return getReadDelegate().getAuthenticationFlowBindingOverrides();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBaseUrl() {
|
||||
return getDelegate().getBaseUrl();
|
||||
return getReadDelegate().getBaseUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientAuthenticatorType() {
|
||||
return getDelegate().getClientAuthenticatorType();
|
||||
return getReadDelegate().getClientAuthenticatorType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientId() {
|
||||
return getDelegate().getClientId();
|
||||
return getReadDelegate().getClientId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> getClientScopes(boolean defaultScope) {
|
||||
return getDelegate().getClientScopes(defaultScope);
|
||||
return getReadDelegate().getClientScopes(defaultScope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Boolean> getClientScopes() {
|
||||
return getReadDelegate().getClientScopes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return getDelegate().getDescription();
|
||||
return getReadDelegate().getDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getManagementUrl() {
|
||||
return getDelegate().getManagementUrl();
|
||||
return getReadDelegate().getManagementUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getDelegate().getName();
|
||||
return getReadDelegate().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNodeReRegistrationTimeout() {
|
||||
return getDelegate().getNodeReRegistrationTimeout();
|
||||
public Integer getNodeReRegistrationTimeout() {
|
||||
return getReadDelegate().getNodeReRegistrationTimeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNotBefore() {
|
||||
return getDelegate().getNotBefore();
|
||||
public Integer getNotBefore() {
|
||||
return getReadDelegate().getNotBefore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocol() {
|
||||
return getDelegate().getProtocol();
|
||||
return getReadDelegate().getProtocol();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolMapperModel getProtocolMapperById(String id) {
|
||||
return getDelegate().getProtocolMapperById(id);
|
||||
public ProtocolMapperModel getProtocolMapper(String id) {
|
||||
return getReadDelegate().getProtocolMapper(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ProtocolMapperModel> getProtocolMappers() {
|
||||
return getDelegate().getProtocolMappers();
|
||||
public Map<String,ProtocolMapperModel> getProtocolMappers() {
|
||||
return getReadDelegate().getProtocolMappers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRealmId() {
|
||||
return getDelegate().getRealmId();
|
||||
return getReadDelegate().getRealmId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRealmId(String realmId) {
|
||||
getWriteDelegate().setRealmId(realmId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getRedirectUris() {
|
||||
return getDelegate().getRedirectUris();
|
||||
return getReadDelegate().getRedirectUris();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRegistrationToken() {
|
||||
return getDelegate().getRegistrationToken();
|
||||
return getReadDelegate().getRegistrationToken();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRootUrl() {
|
||||
return getDelegate().getRootUrl();
|
||||
return getReadDelegate().getRootUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getScope() {
|
||||
return getDelegate().getScope();
|
||||
return getReadDelegate().getScope();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getScopeMappings() {
|
||||
return getDelegate().getScopeMappings();
|
||||
return getReadDelegate().getScopeMappings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSecret() {
|
||||
return getDelegate().getSecret();
|
||||
return getReadDelegate().getSecret();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getWebOrigins() {
|
||||
return getDelegate().getWebOrigins();
|
||||
return getReadDelegate().getWebOrigins();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isAlwaysDisplayInConsole() {
|
||||
return getDelegate().isAlwaysDisplayInConsole();
|
||||
return getWriteDelegate().isAlwaysDisplayInConsole();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isBearerOnly() {
|
||||
return getDelegate().isBearerOnly();
|
||||
return getWriteDelegate().isBearerOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isConsentRequired() {
|
||||
return getDelegate().isConsentRequired();
|
||||
return getWriteDelegate().isConsentRequired();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isDirectAccessGrantsEnabled() {
|
||||
return getDelegate().isDirectAccessGrantsEnabled();
|
||||
return getWriteDelegate().isDirectAccessGrantsEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isEnabled() {
|
||||
return getDelegate().isEnabled();
|
||||
return getWriteDelegate().isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isFrontchannelLogout() {
|
||||
return getDelegate().isFrontchannelLogout();
|
||||
return getWriteDelegate().isFrontchannelLogout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isFullScopeAllowed() {
|
||||
return getDelegate().isFullScopeAllowed();
|
||||
return getWriteDelegate().isFullScopeAllowed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isImplicitFlowEnabled() {
|
||||
return getDelegate().isImplicitFlowEnabled();
|
||||
return getWriteDelegate().isImplicitFlowEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isPublicClient() {
|
||||
return getDelegate().isPublicClient();
|
||||
return getWriteDelegate().isPublicClient();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isServiceAccountsEnabled() {
|
||||
return getDelegate().isServiceAccountsEnabled();
|
||||
return getWriteDelegate().isServiceAccountsEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isStandardFlowEnabled() {
|
||||
return getDelegate().isStandardFlowEnabled();
|
||||
return getWriteDelegate().isStandardFlowEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isSurrogateAuthRequired() {
|
||||
return getDelegate().isSurrogateAuthRequired();
|
||||
return getWriteDelegate().isSurrogateAuthRequired();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String name) {
|
||||
getDelegate().removeAttribute(name);
|
||||
getWriteDelegate().removeAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAuthenticationFlowBindingOverride(String binding) {
|
||||
getDelegate().removeAuthenticationFlowBindingOverride(binding);
|
||||
getWriteDelegate().removeAuthenticationFlowBindingOverride(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeClientScope(String id) {
|
||||
getDelegate().removeClientScope(id);
|
||||
getWriteDelegate().removeClientScope(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeProtocolMapper(String id) {
|
||||
getDelegate().removeProtocolMapper(id);
|
||||
getWriteDelegate().removeProtocolMapper(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRedirectUri(String redirectUri) {
|
||||
getDelegate().removeRedirectUri(redirectUri);
|
||||
getWriteDelegate().removeRedirectUri(redirectUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeWebOrigin(String webOrigin) {
|
||||
getDelegate().removeWebOrigin(webOrigin);
|
||||
getWriteDelegate().removeWebOrigin(webOrigin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlwaysDisplayInConsole(Boolean alwaysDisplayInConsole) {
|
||||
getDelegate().setAlwaysDisplayInConsole(alwaysDisplayInConsole);
|
||||
getWriteDelegate().setAlwaysDisplayInConsole(alwaysDisplayInConsole);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, List<String> values) {
|
||||
getDelegate().setAttribute(name, values);
|
||||
getWriteDelegate().setAttribute(name, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthFlowBindings(Map<String, String> authFlowBindings) {
|
||||
getDelegate().setAuthFlowBindings(authFlowBindings);
|
||||
getWriteDelegate().setAuthFlowBindings(authFlowBindings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthenticationFlowBindingOverride(String binding, String flowId) {
|
||||
getDelegate().setAuthenticationFlowBindingOverride(binding, flowId);
|
||||
getWriteDelegate().setAuthenticationFlowBindingOverride(binding, flowId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBaseUrl(String baseUrl) {
|
||||
getDelegate().setBaseUrl(baseUrl);
|
||||
getWriteDelegate().setBaseUrl(baseUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBearerOnly(Boolean bearerOnly) {
|
||||
getDelegate().setBearerOnly(bearerOnly);
|
||||
getWriteDelegate().setBearerOnly(bearerOnly);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientAuthenticatorType(String clientAuthenticatorType) {
|
||||
getDelegate().setClientAuthenticatorType(clientAuthenticatorType);
|
||||
getWriteDelegate().setClientAuthenticatorType(clientAuthenticatorType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientId(String clientId) {
|
||||
getDelegate().setClientId(clientId);
|
||||
getWriteDelegate().setClientId(clientId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConsentRequired(Boolean consentRequired) {
|
||||
getDelegate().setConsentRequired(consentRequired);
|
||||
getWriteDelegate().setConsentRequired(consentRequired);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDescription(String description) {
|
||||
getDelegate().setDescription(description);
|
||||
getWriteDelegate().setDescription(description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDirectAccessGrantsEnabled(Boolean directAccessGrantsEnabled) {
|
||||
getDelegate().setDirectAccessGrantsEnabled(directAccessGrantsEnabled);
|
||||
getWriteDelegate().setDirectAccessGrantsEnabled(directAccessGrantsEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(Boolean enabled) {
|
||||
getDelegate().setEnabled(enabled);
|
||||
getWriteDelegate().setEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFrontchannelLogout(Boolean frontchannelLogout) {
|
||||
getDelegate().setFrontchannelLogout(frontchannelLogout);
|
||||
getWriteDelegate().setFrontchannelLogout(frontchannelLogout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFullScopeAllowed(Boolean fullScopeAllowed) {
|
||||
getDelegate().setFullScopeAllowed(fullScopeAllowed);
|
||||
getWriteDelegate().setFullScopeAllowed(fullScopeAllowed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImplicitFlowEnabled(Boolean implicitFlowEnabled) {
|
||||
getDelegate().setImplicitFlowEnabled(implicitFlowEnabled);
|
||||
getWriteDelegate().setImplicitFlowEnabled(implicitFlowEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setManagementUrl(String managementUrl) {
|
||||
getDelegate().setManagementUrl(managementUrl);
|
||||
getWriteDelegate().setManagementUrl(managementUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
getDelegate().setName(name);
|
||||
getWriteDelegate().setName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNodeReRegistrationTimeout(int nodeReRegistrationTimeout) {
|
||||
getDelegate().setNodeReRegistrationTimeout(nodeReRegistrationTimeout);
|
||||
public void setNodeReRegistrationTimeout(Integer nodeReRegistrationTimeout) {
|
||||
getWriteDelegate().setNodeReRegistrationTimeout(nodeReRegistrationTimeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNotBefore(int notBefore) {
|
||||
getDelegate().setNotBefore(notBefore);
|
||||
public void setNotBefore(Integer notBefore) {
|
||||
getWriteDelegate().setNotBefore(notBefore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProtocol(String protocol) {
|
||||
getDelegate().setProtocol(protocol);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProtocolMappers(Collection<ProtocolMapperModel> protocolMappers) {
|
||||
getDelegate().setProtocolMappers(protocolMappers);
|
||||
getWriteDelegate().setProtocol(protocol);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPublicClient(Boolean publicClient) {
|
||||
getDelegate().setPublicClient(publicClient);
|
||||
getWriteDelegate().setPublicClient(publicClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRedirectUris(Set<String> redirectUris) {
|
||||
getDelegate().setRedirectUris(redirectUris);
|
||||
getWriteDelegate().setRedirectUris(redirectUris);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRegistrationToken(String registrationToken) {
|
||||
getDelegate().setRegistrationToken(registrationToken);
|
||||
getWriteDelegate().setRegistrationToken(registrationToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRootUrl(String rootUrl) {
|
||||
getDelegate().setRootUrl(rootUrl);
|
||||
getWriteDelegate().setRootUrl(rootUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScope(Set<String> scope) {
|
||||
getDelegate().setScope(scope);
|
||||
getWriteDelegate().setScope(scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSecret(String secret) {
|
||||
getDelegate().setSecret(secret);
|
||||
getWriteDelegate().setSecret(secret);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setServiceAccountsEnabled(Boolean serviceAccountsEnabled) {
|
||||
getDelegate().setServiceAccountsEnabled(serviceAccountsEnabled);
|
||||
getWriteDelegate().setServiceAccountsEnabled(serviceAccountsEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStandardFlowEnabled(Boolean standardFlowEnabled) {
|
||||
getDelegate().setStandardFlowEnabled(standardFlowEnabled);
|
||||
getWriteDelegate().setStandardFlowEnabled(standardFlowEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSurrogateAuthRequired(Boolean surrogateAuthRequired) {
|
||||
getDelegate().setSurrogateAuthRequired(surrogateAuthRequired);
|
||||
getWriteDelegate().setSurrogateAuthRequired(surrogateAuthRequired);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWebOrigins(Set<String> webOrigins) {
|
||||
getDelegate().setWebOrigins(webOrigins);
|
||||
getWriteDelegate().setWebOrigins(webOrigins);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProtocolMapper(String id, ProtocolMapperModel mapping) {
|
||||
getDelegate().updateProtocolMapper(id, mapping);
|
||||
public void setProtocolMapper(String id, ProtocolMapperModel mapping) {
|
||||
getWriteDelegate().setProtocolMapper(id, mapping);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return getDelegate().getId();
|
||||
return getReadDelegate().getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUpdated() {
|
||||
return getDelegate().isUpdated();
|
||||
return isWriteDelegateInitialized() && getWriteDelegate().isUpdated();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -140,7 +140,8 @@ public class MapClientProvider implements ClientProvider {
|
|||
public ClientModel addClient(RealmModel realm, String id, String clientId) {
|
||||
LOG.tracef("addClient(%s, %s, %s)%s", realm, id, clientId, getShortStackTrace());
|
||||
|
||||
MapClientEntity entity = new MapClientEntityImpl(id, realm.getId());
|
||||
MapClientEntity entity = new MapClientEntityImpl(id);
|
||||
entity.setRealmId(realm.getId());
|
||||
entity.setClientId(clientId);
|
||||
entity.setEnabled(true);
|
||||
entity.setStandardFlowEnabled(true);
|
||||
|
@ -294,7 +295,7 @@ public class MapClientProvider implements ClientProvider {
|
|||
clientScopes.stream()
|
||||
.filter(clientScope -> ! existingClientScopes.containsKey(clientScope.getName()))
|
||||
.filter(clientScope -> Objects.equals(clientScope.getProtocol(), clientProtocol))
|
||||
.forEach(clientScope -> entity.addClientScope(clientScope.getId(), defaultScope));
|
||||
.forEach(clientScope -> entity.setClientScope(clientScope.getId(), defaultScope));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -29,6 +29,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||
import com.fasterxml.jackson.databind.ObjectReader;
|
||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.databind.type.TypeFactory;
|
||||
import com.fasterxml.jackson.datatype.jdk8.StreamSerializer;
|
||||
|
@ -51,6 +52,7 @@ public class Serialization {
|
|||
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
|
||||
.setVisibility(PropertyAccessor.ALL, Visibility.NONE)
|
||||
.setVisibility(PropertyAccessor.FIELD, Visibility.ANY)
|
||||
.activateDefaultTyping(new LaissezFaireSubTypeValidator() /* TODO - see javadoc */, ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT, JsonTypeInfo.As.PROPERTY)
|
||||
.addMixIn(UpdatableEntity.class, IgnoreUpdatedMixIn.class)
|
||||
.addMixIn(AbstractEntity.class, AbstractEntityMixIn.class)
|
||||
;
|
||||
|
|
|
@ -62,16 +62,17 @@ public class ConcurrentHashMapKeycloakTransaction<K, V extends AbstractEntity &
|
|||
|
||||
@Override
|
||||
public void commit() {
|
||||
log.tracef("Commit - %s", map);
|
||||
|
||||
if (rollback) {
|
||||
throw new RuntimeException("Rollback only!");
|
||||
}
|
||||
|
||||
if (! tasks.isEmpty()) {
|
||||
log.tracef("Commit - %s", map);
|
||||
for (MapTaskWithValue value : tasks.values()) {
|
||||
value.execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback() {
|
||||
|
|
|
@ -66,7 +66,9 @@ import java.util.function.Predicate;
|
|||
import java.util.stream.Stream;
|
||||
|
||||
import org.keycloak.models.map.storage.CriterionNotSupportedException;
|
||||
import java.util.Collections;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Optional;
|
||||
import static org.keycloak.models.UserSessionModel.CORRESPONDING_SESSION_ID;
|
||||
|
||||
/**
|
||||
|
@ -261,14 +263,14 @@ public class MapFieldPredicates {
|
|||
private static MapModelCriteriaBuilder<Object, MapClientEntity, ClientModel> checkScopeMappingRole(MapModelCriteriaBuilder<Object, MapClientEntity, ClientModel> mcb, Operator op, Object[] values) {
|
||||
String roleIdS = ensureEqSingleValue(ClientModel.SearchableFields.SCOPE_MAPPING_ROLE, "role_id", op, values);
|
||||
Function<MapClientEntity, ?> getter;
|
||||
getter = ce -> ce.getScopeMappings().contains(roleIdS);
|
||||
getter = ce -> Optional.ofNullable(ce.getScopeMappings()).orElse(Collections.emptyList()).contains(roleIdS);
|
||||
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
|
||||
}
|
||||
|
||||
private static MapModelCriteriaBuilder<Object, MapGroupEntity, GroupModel> checkGrantedGroupRole(MapModelCriteriaBuilder<Object, MapGroupEntity, GroupModel> mcb, Operator op, Object[] values) {
|
||||
String roleIdS = ensureEqSingleValue(GroupModel.SearchableFields.ASSIGNED_ROLE, "role_id", op, values);
|
||||
Function<MapGroupEntity, ?> getter;
|
||||
getter = ge -> ge.getGrantedRoles().contains(roleIdS);
|
||||
getter = ge -> Optional.ofNullable(ge.getGrantedRoles()).orElse(Collections.emptySet()).contains(roleIdS);
|
||||
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
|
||||
}
|
||||
|
||||
|
|
|
@ -34,5 +34,6 @@
|
|||
<module>jpa</module>
|
||||
<module>infinispan</module>
|
||||
<module>map</module>
|
||||
<module>build-processor</module>
|
||||
</modules>
|
||||
</project>
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.models;
|
|||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Specifies a mapping from user data to a protocol claim assertion.
|
||||
|
@ -78,16 +79,41 @@ public class ProtocolMapperModel implements Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
ProtocolMapperModel that = (ProtocolMapperModel) o;
|
||||
|
||||
if (!id.equals(that.id)) return false;
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final ProtocolMapperModel other = (ProtocolMapperModel) obj;
|
||||
if (this.consentRequired != other.consentRequired) {
|
||||
return false;
|
||||
}
|
||||
if ( ! Objects.equals(this.id, other.id)) {
|
||||
return false;
|
||||
}
|
||||
if ( ! Objects.equals(this.name, other.name)) {
|
||||
return false;
|
||||
}
|
||||
if ( ! Objects.equals(this.protocol, other.protocol)) {
|
||||
return false;
|
||||
}
|
||||
if ( ! Objects.equals(this.protocolMapper, other.protocolMapper)) {
|
||||
return false;
|
||||
}
|
||||
if ( ! Objects.equals(this.consentText, other.consentText)) {
|
||||
return false;
|
||||
}
|
||||
if ( ! Objects.equals(this.config, other.config)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
|
|
@ -117,9 +117,12 @@ public class MapStorageTest extends KeycloakModelTest {
|
|||
assertClientDoesNotExist(storage2, idMain, kcMain, kc2);
|
||||
assertClientDoesNotExist(storage2, id1, kc1, kc2);
|
||||
|
||||
MapClientEntity clientMain = new MapClientEntityImpl(idMain, realmId);
|
||||
MapClientEntity client1 = new MapClientEntityImpl(id1, realmId);
|
||||
MapClientEntity client2 = new MapClientEntityImpl(id2, realmId);
|
||||
MapClientEntity clientMain = new MapClientEntityImpl(idMain);
|
||||
clientMain.setRealmId(realmId);
|
||||
MapClientEntity client1 = new MapClientEntityImpl(id1);
|
||||
client1.setRealmId(realmId);
|
||||
MapClientEntity client2 = new MapClientEntityImpl(id2);
|
||||
client2.setRealmId(realmId);
|
||||
|
||||
clientMain = storageMain.create(clientMain);
|
||||
client1 = storage1.create(client1);
|
||||
|
|
Loading…
Reference in a new issue