ServicesUtilsFuzzer.java
// Copyright 2023 the cncf-fuzzing authors
//
// 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.
//
///////////////////////////////////////////////////////////////////////////
import com.code_intelligence.jazzer.api.FuzzedDataProvider;
import java.io.ByteArrayInputStream;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.util.stream.Stream;
import org.keycloak.models.GroupModel;
import org.keycloak.models.OTPPolicy;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.services.DefaultKeycloakSession;
import org.keycloak.services.DefaultKeycloakSessionFactory;
import org.keycloak.services.resources.admin.permissions.GroupPermissionEvaluator;
import org.keycloak.utils.CRLUtils;
import org.keycloak.utils.GroupUtils;
import org.keycloak.utils.RegexUtils;
import org.keycloak.utils.SearchQueryUtils;
import org.keycloak.utils.TotpUtils;
import org.mockito.Mockito;
/** This fuzzer targets the methods in different util classes in the services utils package. */
public class ServicesUtilsFuzzer {
private static CertificateFactory cf;
private static DefaultKeycloakSession session;
public static void fuzzerInitialize() {
try {
// Initialize certificate factory
cf = CertificateFactory.getInstance("X.509");
// Initialize KeycloakSession
DefaultKeycloakSessionFactory dksf = new DefaultKeycloakSessionFactory();
session = new DefaultKeycloakSession(dksf);
} catch (CertificateException e) {
// Directly exit if initialisation fails
throw new RuntimeException(e);
}
}
public static void fuzzerTestOneInput(FuzzedDataProvider data) {
try {
// Randomly choose which utils method to invoke
Integer choice = data.consumeInt(1, 7);
switch (choice) {
case 1:
// Create certificate and crl from random data
X509Certificate[] certs = new X509Certificate[3];
for (int i = 0; i < 3; i++) {
certs[i] =
(X509Certificate)
cf.generateCertificate(
new ByteArrayInputStream(data.consumeBytes(data.remainingBytes() / 2)));
}
X509CRL crl =
(X509CRL) cf.generateCRL(new ByteArrayInputStream(data.consumeRemainingAsBytes()));
// Call target method
CRLUtils.check(certs, crl, session);
break;
case 2:
// Create and mock GroupModel instance with random data
GroupModel group = Mockito.mock(GroupModel.class);
Mockito.when(group.getId()).thenReturn(data.consumeString(data.remainingBytes() / 2));
Mockito.when(group.getName()).thenReturn(data.consumeString(data.remainingBytes() / 2));
Mockito.when(group.getParent()).thenReturn(null);
Stream.Builder<GroupModel> builder = Stream.builder();
Mockito.when(group.getSubGroupsStream()).thenReturn(builder.build());
Map<String, List<String>> attributeMap = new HashMap<String, List<String>>();
attributeMap.put(
data.consumeString(data.remainingBytes() / 2),
List.of(data.consumeString(data.remainingBytes() / 2)));
Mockito.when(group.getAttributes()).thenReturn(attributeMap);
// Create and mock GroupPermissionEvaluator instance with random data
GroupPermissionEvaluator groupPermissions = Mockito.mock(GroupPermissionEvaluator.class);
Mockito.when(groupPermissions.canList()).thenReturn(data.consumeBoolean());
Mockito.when(groupPermissions.canManage(group)).thenReturn(data.consumeBoolean());
Mockito.when(groupPermissions.canView(group)).thenReturn(data.consumeBoolean());
Mockito.when(groupPermissions.canManage()).thenReturn(data.consumeBoolean());
Mockito.when(groupPermissions.canView()).thenReturn(data.consumeBoolean());
Mockito.when(groupPermissions.getGroupsWithViewPermission(group))
.thenReturn(data.consumeBoolean());
Mockito.when(groupPermissions.canManageMembership(group))
.thenReturn(data.consumeBoolean());
Mockito.when(groupPermissions.canViewMembers(group)).thenReturn(data.consumeBoolean());
Map<String, Boolean> permissionMap = new HashMap<String, Boolean>();
permissionMap.put(data.consumeString(data.remainingBytes() / 2), data.consumeBoolean());
Mockito.when(groupPermissions.getAccess(group)).thenReturn(permissionMap);
Set<String> set = new HashSet<String>();
set.add(data.consumeString(data.remainingBytes() / 2));
Mockito.when(groupPermissions.getGroupsWithViewPermission()).thenReturn(set);
// Create and mock RealmModel instance with default policy and random data
RealmModel realm = Mockito.mock(RealmModel.class);
// Retrieve random boolean data
Boolean full = data.consumeBoolean();
// Call target method
try {
GroupUtils.populateGroupHierarchyFromSubGroups(
session, realm, Stream.of(group), full, groupPermissions);
} catch (NullPointerException e) {
// Handle the case when the execution environment don't have any profile instance
if (!e.toString()
.contains(
"the return value of \"org.keycloak.common.Profile.getInstance()\" is null")) {
throw e;
}
}
break;
case 3:
// Call target method
RegexUtils.valueMatchesRegex(
Pattern.quote(data.consumeString(data.remainingBytes() / 2)),
data.consumeRemainingAsString());
break;
case 4:
// Call target method
SearchQueryUtils.getFields(data.consumeRemainingAsString());
break;
case 5:
// Call target method
SearchQueryUtils.unescape(data.consumeRemainingAsString());
break;
case 6:
// Call target method
TotpUtils.encode(data.consumeRemainingAsString());
break;
case 7:
// Create and mock UserModel instance with random data
UserModel userModel = Mockito.mock(UserModel.class);
Mockito.when(userModel.getUsername())
.thenReturn(data.consumeString(data.remainingBytes() / 2));
// Create and mock RealmModel instance with default policy and random data
RealmModel realmModel = Mockito.mock(RealmModel.class);
Mockito.when(realmModel.getOTPPolicy()).thenReturn(OTPPolicy.DEFAULT_POLICY);
Mockito.when(realmModel.getName())
.thenReturn(data.consumeString(data.remainingBytes() / 2));
// Call target method
TotpUtils.qrCode(data.consumeRemainingAsString(), realmModel, userModel);
break;
}
} catch (GeneralSecurityException | PatternSyntaxException e) {
// Known exception
} catch (RuntimeException e) {
if (!e.getMessage().contains("com.google.zxing.WriterException")) {
// Unknown internal exception
throw e;
}
}
}
}