Skip to content

Commit 831365d

Browse files
authored
Add verbose logging in MDG filtering (#1576)
* Add verbose printing in MDG * Rename flag reading function in MDG * Add 'verbose' prefix
1 parent f21560a commit 831365d

File tree

11 files changed

+152
-38
lines changed

11 files changed

+152
-38
lines changed

test-app/app/build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ def computeBuildToolsVersion = { ->
8484
}
8585

8686
def enableAnalytics = (project.hasProperty("gatherAnalyticsData") && project.gatherAnalyticsData == "true")
87+
def enableVerboseMDG = project.gradle.startParameter.logLevel.name() == 'DEBUG'
8788
def analyticsFilePath = "$rootDir/analytics/build-statistics.json"
8889
def analyticsCollector = project.ext.AnalyticsCollector.withOutputPath(analyticsFilePath)
8990
if (enableAnalytics) {
@@ -823,6 +824,10 @@ task buildMetadata(type: BuildToolTask) {
823824
paramz.add("analyticsFilePath=$analyticsFilePath")
824825
}
825826

827+
if(enableVerboseMDG){
828+
paramz.add("verbose")
829+
}
830+
826831
args paramz.toArray()
827832
}
828833
}

test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/Builder.java

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,7 @@ static TreeNode build(List<String> paths) throws Exception {
6767
for (String className : classNames) {
6868
try {
6969
SecuredNativeClassDescriptor clazz = SecuredClassRepository.INSTANCE.findClass(className);
70-
if (!clazz.isUsageAllowed()) {
71-
throwMetadataSecurityViolationException(className);
72-
} else {
70+
if (clazz.isUsageAllowed()) {
7371
tryCollectKotlinExtensionFunctions(clazz.getNativeDescriptor());
7472
}
7573
} catch (Throwable e) {
@@ -90,9 +88,7 @@ static TreeNode build(List<String> paths) throws Exception {
9088
// Class<?> clazz = Class.forName(className, false, loader);
9189

9290
SecuredNativeClassDescriptor clazz = SecuredClassRepository.INSTANCE.findClass(className);
93-
if (!clazz.isUsageAllowed()) {
94-
throwMetadataSecurityViolationException(className);
95-
} else {
91+
if (clazz.isUsageAllowed()) {
9692
generate(clazz.getNativeDescriptor(), root);
9793
}
9894
} catch (Throwable e) {
@@ -106,10 +102,6 @@ static TreeNode build(List<String> paths) throws Exception {
106102
return root;
107103
}
108104

109-
private static void throwMetadataSecurityViolationException(String className){
110-
throw new MetadataSecurityViolationException("Class " + className + " could not be used!");
111-
}
112-
113105
private static void tryCollectKotlinExtensionFunctions(NativeClassDescriptor classDescriptor) {
114106
if (classDescriptor instanceof KotlinClassDescriptor) {
115107
ExtensionFunctionsCollector extensionFunctionsCollector = new BytecodeExtensionFunctionsCollector(new BytecodeClassMetadataParser());

test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/Generator.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.telerik.metadata.analytics.AnalyticsConfiguration;
44
import com.telerik.metadata.security.filtering.input.user.UserPatternsCollection;
5+
import com.telerik.metadata.security.logging.console.MetadataFilterConsoleLogger;
56

67
import java.io.BufferedReader;
78
import java.io.File;
@@ -15,6 +16,7 @@
1516

1617
public class Generator {
1718

19+
private static final String VERBOSE_FLAG_NAME = "verbose";
1820
private static final String ANALYTICS_ARGUMENT_BEGINNING = "analyticsFilePath=";
1921
private static final String MDG_OUTPUT_DIR = "mdg-output-dir.txt";
2022
private static final String MDG_JAVA_DEPENDENCIES = "mdg-java-dependencies.txt";
@@ -25,7 +27,7 @@ public class Generator {
2527
* @param args
2628
*/
2729
public static void main(String[] args) {
28-
enableAnalyticsBasedOnArgs(args);
30+
enableFlaggedFeatures(args);
2931
UserPatternsCollection.INSTANCE.populateWhitelistEntriesFromFile(MDG_WHITELIST);
3032
UserPatternsCollection.INSTANCE.populateBlacklistEntriesFromFile(MDG_BLACKLIST);
3133

@@ -63,17 +65,19 @@ public static void main(String[] args) {
6365
}
6466
}
6567

66-
private static void enableAnalyticsBasedOnArgs(String[] args){
68+
private static void enableFlaggedFeatures(String[] args) {
6769
for (String arg : args) {
6870
if (arg.startsWith(ANALYTICS_ARGUMENT_BEGINNING)) {
6971
String filePath = arg.replace(ANALYTICS_ARGUMENT_BEGINNING, "");
7072
AnalyticsConfiguration.enableAnalytics(filePath);
73+
} else if (VERBOSE_FLAG_NAME.equals(arg)) {
74+
MetadataFilterConsoleLogger.INSTANCE.setEnabled(true);
7175
}
7276
}
7377
}
7478

7579
public static List<String> getFileRows(String filename) throws IOException {
76-
List<String> rows = new ArrayList<String>();
80+
List<String> rows = new ArrayList<>();
7781
BufferedReader br = null;
7882
try {
7983
br = new BufferedReader(new InputStreamReader(new FileInputStream(filename)));

test-app/build-tools/android-metadata-generator/src/src/com/telerik/metadata/security/classes/SecuredClassRepository.kt

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,32 @@ import com.telerik.metadata.security.filtering.blacklisting.MetadataBlacklist
66
import com.telerik.metadata.security.filtering.input.user.UserPatternsCollection
77
import com.telerik.metadata.security.filtering.matching.impl.PatternMatcherImpl
88
import com.telerik.metadata.security.filtering.whitelisting.MetadataWhitelist
9+
import com.telerik.metadata.security.logging.console.MetadataFilterConsoleLogger
910
import java.util.*
11+
import kotlin.collections.HashSet
1012

1113
object SecuredClassRepository {
1214
private val cachedProviders = ArrayList<ClassMapProvider>()
1315
private val patternMatcher = PatternMatcherImpl()
1416
private val whitelist = MetadataWhitelist(UserPatternsCollection.whitelistEntries, patternMatcher)
1517
private val blacklist = MetadataBlacklist(UserPatternsCollection.blacklistEntries, patternMatcher)
18+
private val alreadyLoggedClasses = HashSet<Pair<String, String>>()
1619

1720
fun addToCache(classMapProvider: ClassMapProvider) {
1821
cachedProviders.add(classMapProvider)
1922
}
2023

24+
private fun NativeClassDescriptor.getSimplifiedClassName() = this.className.substring(this.packageName.length).replace('$', '.').trimStart('.')
25+
2126
fun findClass(className: String): SecuredNativeClassDescriptor {
2227
val clazz: NativeClassDescriptor? = findClassFromProviders(className)
2328

2429
if (clazz != null) {
25-
val simplifiedClassName = clazz.className.substring(clazz.packageName.length).replace('$', '.').trimStart('.')
26-
27-
val isAllowedByWhitelist = whitelist.isAllowed(clazz.packageName, simplifiedClassName)
28-
if (isAllowedByWhitelist) {
30+
val simplifiedClassName = clazz.getSimplifiedClassName()
2931

30-
val isAllowedByBlacklist = blacklist.isAllowed(clazz.packageName, simplifiedClassName)
31-
if (isAllowedByBlacklist) {
32-
return SecuredNativeClassDescriptor(true, clazz)
33-
}
32+
val isUsageAllowed = isClassUsageAllowed(clazz.packageName, simplifiedClassName)
33+
if (isUsageAllowed) {
34+
return SecuredNativeClassDescriptor(true, clazz)
3435
}
3536
}
3637

@@ -41,15 +42,11 @@ object SecuredClassRepository {
4142
var clazz: NativeClassDescriptor? = findClassFromProviders(className)
4243

4344
while (clazz != null) {
44-
val simplifiedClassName = clazz.className.substring(clazz.packageName.length).replace('$', '.').trimStart('.')
45+
val simplifiedClassName = clazz.getSimplifiedClassName()
4546

46-
val isAllowedByWhitelist = whitelist.isAllowed(clazz.packageName, simplifiedClassName)
47-
if (isAllowedByWhitelist) {
48-
49-
val isAllowedByBlacklist = blacklist.isAllowed(clazz.packageName, simplifiedClassName)
50-
if (isAllowedByBlacklist) {
51-
return SecuredNativeClassDescriptor(true, clazz)
52-
}
47+
val isUsageAllowed = isClassUsageAllowed(clazz.packageName, simplifiedClassName)
48+
if (isUsageAllowed) {
49+
return SecuredNativeClassDescriptor(true, clazz)
5350
}
5451

5552
clazz = findClassFromProviders(clazz.superclassName)
@@ -58,6 +55,29 @@ object SecuredClassRepository {
5855
return SecuredNativeClassDescriptor(false, NativeClassDescriptor.Missing)
5956
}
6057

58+
private fun isClassUsageAllowed(packageName: String, className: String): Boolean {
59+
val whitelistFilterResult = whitelist.isAllowed(packageName, className)
60+
val blacklistFilterResult = blacklist.isAllowed(packageName, className)
61+
62+
val packageAndClassNamePair = packageName to className
63+
64+
if (whitelistFilterResult.isAllowed && blacklistFilterResult.isAllowed) {
65+
if (packageAndClassNamePair !in alreadyLoggedClasses) {
66+
MetadataFilterConsoleLogger.logAllowed(packageName, className, whitelistFilterResult, blacklistFilterResult)
67+
alreadyLoggedClasses.add(packageAndClassNamePair)
68+
}
69+
70+
return true
71+
}
72+
73+
if (packageAndClassNamePair !in alreadyLoggedClasses) {
74+
MetadataFilterConsoleLogger.logDisallowed(packageName, className, whitelistFilterResult, blacklistFilterResult)
75+
alreadyLoggedClasses.add(packageAndClassNamePair)
76+
}
77+
78+
return false
79+
}
80+
6181
private fun findClassFromProviders(className: String): NativeClassDescriptor? {
6282
var clazz: NativeClassDescriptor? = null
6383
for (classMapProvider in cachedProviders) {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package com.telerik.metadata.security.filtering
22

33
interface MetadataFilter {
4-
fun isAllowed(packageName: String, className: String): Boolean
4+
fun isAllowed(packageName: String, className: String): MetadataFilterResult
55
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.telerik.metadata.security.filtering
2+
3+
import com.telerik.metadata.security.filtering.input.PatternEntry
4+
import java.util.*
5+
6+
data class MetadataFilterResult(val isAllowed: Boolean, val matchedPatternEntry: Optional<PatternEntry> = Optional.empty())
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
package com.telerik.metadata.security.filtering.blacklisting
22

33
import com.telerik.metadata.security.filtering.MetadataFilter
4+
import com.telerik.metadata.security.filtering.MetadataFilterResult
45
import com.telerik.metadata.security.filtering.input.PatternEntry
56
import com.telerik.metadata.security.filtering.matching.PatternMatcher
7+
import java.util.*
68

79
class MetadataBlacklist(private val userInput: Collection<PatternEntry>, private val patternMatcher: PatternMatcher) : MetadataFilter {
810

9-
override fun isAllowed(packageName: String, className: String) = !userInput.any { inputEntry ->
10-
(inputEntry.packagePattern.isEmpty() || patternMatcher.match(inputEntry.packagePattern, packageName))
11-
&& (inputEntry.classPattern.isEmpty() || patternMatcher.match(inputEntry.classPattern, className))
11+
override fun isAllowed(packageName: String, className: String): MetadataFilterResult {
12+
val responsiblePatternEntry = userInput.firstOrNull { inputEntry ->
13+
(inputEntry.packagePattern.isEmpty() || patternMatcher.match(inputEntry.packagePattern, packageName))
14+
&& (inputEntry.classPattern.isEmpty() || patternMatcher.match(inputEntry.classPattern, className))
15+
}
16+
17+
return if (responsiblePatternEntry != null) MetadataFilterResult(false, Optional.of(responsiblePatternEntry)) else MetadataFilterResult(true)
1218
}
1319
}
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
package com.telerik.metadata.security.filtering.input
22

3-
data class PatternEntry(val packagePattern: String, val classPattern: String)
3+
data class PatternEntry(val packagePattern: String, val classPattern: String) {
4+
companion object {
5+
fun empty(): PatternEntry {
6+
return PatternEntry("", "")
7+
}
8+
}
9+
10+
override fun toString() = "$packagePattern:$classPattern"
11+
}
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
package com.telerik.metadata.security.filtering.whitelisting
22

33
import com.telerik.metadata.security.filtering.MetadataFilter
4+
import com.telerik.metadata.security.filtering.MetadataFilterResult
45
import com.telerik.metadata.security.filtering.input.PatternEntry
56
import com.telerik.metadata.security.filtering.matching.PatternMatcher
7+
import java.util.*
68

79
class MetadataWhitelist(private val userInput: Collection<PatternEntry>, private val patternMatcher: PatternMatcher) : MetadataFilter {
810

9-
override fun isAllowed(packageName: String, className: String) = userInput.any { inputEntry ->
10-
(inputEntry.packagePattern.isEmpty() || patternMatcher.match(inputEntry.packagePattern, packageName))
11-
&& (inputEntry.classPattern.isEmpty() || patternMatcher.match(inputEntry.classPattern, className))
12-
}
11+
override fun isAllowed(packageName: String, className: String): MetadataFilterResult {
12+
val responsiblePatternEntry = userInput.firstOrNull { inputEntry ->
13+
(inputEntry.packagePattern.isEmpty() || patternMatcher.match(inputEntry.packagePattern, packageName))
14+
&& (inputEntry.classPattern.isEmpty() || patternMatcher.match(inputEntry.classPattern, className))
15+
}
1316

17+
return if (responsiblePatternEntry != null) MetadataFilterResult(true, Optional.of(responsiblePatternEntry)) else MetadataFilterResult(false)
18+
}
1419

1520
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.telerik.metadata.security.logging
2+
3+
import com.telerik.metadata.security.filtering.MetadataFilterResult
4+
5+
interface MetadataFilterLogger {
6+
fun logAllowed(packageName: String, className: String, whitelistFilterResult: MetadataFilterResult, blacklistFilterResult: MetadataFilterResult)
7+
fun logDisallowed(packageName: String, className: String, whitelistFilterResult: MetadataFilterResult, blacklistFilterResult: MetadataFilterResult)
8+
}

0 commit comments

Comments
 (0)