22
22
import java .net .URI ;
23
23
import java .net .URISyntaxException ;
24
24
import java .util .Arrays ;
25
- import java .util .HashMap ;
26
25
import java .util .List ;
27
26
import java .util .Map ;
28
27
import java .util .Objects ;
41
40
import org .sonar .plugins .python .api .tree .CallExpression ;
42
41
import org .sonar .plugins .python .api .tree .ClassDef ;
43
42
import org .sonar .plugins .python .api .tree .Expression ;
44
- import org .sonar .plugins .python .api .tree .FunctionDef ;
45
43
import org .sonar .plugins .python .api .tree .HasSymbol ;
46
44
import org .sonar .plugins .python .api .tree .Name ;
47
45
import org .sonar .plugins .python .api .tree .QualifiedExpression ;
56
54
public class ClearTextProtocolsCheck extends PythonSubscriptionCheck {
57
55
private static final List <String > SENSITIVE_PROTOCOLS = Arrays .asList ("http://" , "ftp://" , "telnet://" );
58
56
private static final Pattern LOOPBACK = Pattern .compile ("localhost|127(?:\\ .[0-9]+){0,2}\\ .[0-9]+$|^(?:0*\\ :)*?:?0*1" , Pattern .CASE_INSENSITIVE );
59
- private static final Map <String , String > ALTERNATIVES = new HashMap <>();
60
- private static final String SENSITIVE_HTTP_SERVER_CALL = "socketserver.BaseServer.serve_forever" ;
57
+ private static final Map <String , String > ALTERNATIVES = Map .of (
58
+ "http" , "https" ,
59
+ "ftp" , "sftp, scp or ftps" ,
60
+ "telnet" , "ssh" );
61
+ private static final String SENSITIVE_HTTP_SERVER_START_FQN = "socketserver.BaseServer.serve_forever" ;
62
+ private static final String SENSITIVE_HTTP_SERVER_BIND_FQN = "socketserver.BaseServer.server_bind" ;
63
+ private static final Set <String > SENSITIVE_HTTP_SERVER_METHOD_NAMES = Set .of ("serve_forever" , "server_bind" );
61
64
private static final Set <String > SENSITIVE_HTTP_SERVER_CLASSES = Set .of ("http.server.HTTPServer" , "http.server.ThreadingHTTPServer" );
62
65
63
-
64
- static {
65
- ALTERNATIVES .put ("http" , "https" );
66
- ALTERNATIVES .put ("ftp" , "sftp, scp or ftps" );
67
- ALTERNATIVES .put ("telnet" , "ssh" );
68
- }
69
-
70
66
@ Override
71
67
public void initialize (Context context ) {
72
68
context .registerSyntaxNodeConsumer (Tree .Kind .STRING_ELEMENT , ctx -> {
@@ -89,28 +85,27 @@ public void initialize(Context context) {
89
85
90
86
context .registerSyntaxNodeConsumer (Tree .Kind .QUALIFIED_EXPR , ClearTextProtocolsCheck ::checkServerCallFromSuper );
91
87
92
- context .registerSyntaxNodeConsumer (Tree .Kind .FUNCDEF , ClearTextProtocolsCheck ::checkServerBindOverrides );
88
+ context .registerSyntaxNodeConsumer (Tree .Kind .CALL_EXPR , ClearTextProtocolsCheck ::checkServerBindCalls );
89
+
93
90
new ClearTextProtocolsCheckPart ().initialize (context );
94
91
}
95
92
96
93
private static void checkServerCallFromSuper (SubscriptionContext ctx ) {
97
94
QualifiedExpression qualifiedExpression = (QualifiedExpression ) ctx .syntaxNode ();
98
95
Optional .of (qualifiedExpression )
99
- .filter (qe -> isName ("serve_forever" , qe .name ()) && isCallToSensitiveSuperClass (qe ))
96
+ .filter (qe -> SENSITIVE_HTTP_SERVER_METHOD_NAMES .contains (qe .name ().name ()))
97
+ .filter (ClearTextProtocolsCheck ::isCallToSensitiveSuperClass )
100
98
.map (qe -> TreeUtils .firstAncestorOfKind (qe , Tree .Kind .CALL_EXPR ))
101
99
.flatMap (TreeUtils .toOptionalInstanceOfMapper (CallExpression .class ))
102
100
.ifPresent (ce -> ctx .addIssue (ce , message ("http" )));
103
101
}
104
102
105
- private static void checkServerBindOverrides (SubscriptionContext ctx ) {
106
- FunctionDef funcDef = (FunctionDef ) ctx .syntaxNode ();
107
- Optional .of (funcDef )
108
- .filter (fd -> isName ("server_bind" , fd .name ()) && isParentClassExtendingSensitiveClass (funcDef ))
109
- .ifPresent (fd -> ctx .addIssue (fd .defKeyword (), fd .rightPar (), message ("http" )));
110
- }
111
-
112
- private static boolean isName (String nameToCheck , Name name ) {
113
- return nameToCheck .equals (name .name ());
103
+ private static void checkServerBindCalls (SubscriptionContext ctx ) {
104
+ CallExpression callExpression = (CallExpression ) ctx .syntaxNode ();
105
+ Optional .ofNullable (callExpression .calleeSymbol ())
106
+ .map (Symbol ::fullyQualifiedName )
107
+ .filter (fqn -> SENSITIVE_HTTP_SERVER_BIND_FQN .equals (fqn ) && isParentClassExtendingSensitiveClass (callExpression ))
108
+ .ifPresent (fqn -> ctx .addIssue (callExpression , message ("http" )));
114
109
}
115
110
116
111
private static boolean isCallToSensitiveSuperClass (QualifiedExpression expression ) {
@@ -205,7 +200,7 @@ private static Optional<String> isUnsafeLib(String qualifiedName) {
205
200
if ("ftplib.FTP" .equals (qualifiedName )) {
206
201
return Optional .of ("ftp" );
207
202
}
208
- if (SENSITIVE_HTTP_SERVER_CALL .equals (qualifiedName )) {
203
+ if (SENSITIVE_HTTP_SERVER_START_FQN .equals (qualifiedName )) {
209
204
return Optional .of ("http" );
210
205
}
211
206
return Optional .empty ();
0 commit comments