@@ -39,8 +39,8 @@ func TestPerformDCR_PublicClient(t *testing.T) {
3939		Scopes :                []string {"read" , "write" },
4040	}
4141
42- 	// Perform DCR 
43- 	creds , err  :=  PerformDCR (context .Background (), discovery , "test-server" )
42+ 	// Perform DCR (empty redirectURI uses default)  
43+ 	creds , err  :=  PerformDCR (context .Background (), discovery , "test-server" ,  "" )
4444	// Verify no error 
4545	if  err  !=  nil  {
4646		t .Fatalf ("DCR failed: %v" , err )
@@ -82,8 +82,8 @@ func TestPerformDCR_NoRegistrationEndpoint(t *testing.T) {
8282		RegistrationEndpoint :  "" , // Empty - DCR not supported 
8383	}
8484
85- 	// Attempt DCR 
86- 	creds , err  :=  PerformDCR (context .Background (), discovery , "test-server" )
85+ 	// Attempt DCR (empty redirectURI uses default)  
86+ 	creds , err  :=  PerformDCR (context .Background (), discovery , "test-server" ,  "" )
8787
8888	// Verify error occurred 
8989	if  err  ==  nil  {
@@ -93,3 +93,86 @@ func TestPerformDCR_NoRegistrationEndpoint(t *testing.T) {
9393		t .Error ("Expected nil credentials on error" )
9494	}
9595}
96+ 
97+ // TestIsValidRedirectURI verifies redirect URI validation logic 
98+ func  TestIsValidRedirectURI (t  * testing.T ) {
99+ 	tests  :=  []struct  {
100+ 		name         string 
101+ 		redirectURI  string 
102+ 		expectError  bool 
103+ 		description  string 
104+ 	}{
105+ 		{
106+ 			name :        "empty string" ,
107+ 			redirectURI : "" ,
108+ 			expectError : false ,
109+ 			description : "Empty string should be allowed (uses default)" ,
110+ 		},
111+ 		{
112+ 			name :        "localhost http" ,
113+ 			redirectURI : "http://localhost:5000/callback" ,
114+ 			expectError : false ,
115+ 			description : "Localhost with HTTP should be allowed" ,
116+ 		},
117+ 		{
118+ 			name :        "localhost https" ,
119+ 			redirectURI : "https://localhost:5000/callback" ,
120+ 			expectError : false ,
121+ 			description : "Localhost with HTTPS should be allowed" ,
122+ 		},
123+ 		{
124+ 			name :        "127.0.0.1" ,
125+ 			redirectURI : "http://127.0.0.1:8080/callback" ,
126+ 			expectError : false ,
127+ 			description : "127.0.0.1 should be allowed" ,
128+ 		},
129+ 		{
130+ 			name :        "IPv6 localhost" ,
131+ 			redirectURI : "http://[::1]:8080/callback" ,
132+ 			expectError : false ,
133+ 			description : "IPv6 localhost should be allowed" ,
134+ 		},
135+ 		{
136+ 			name :        "mcp.docker.com production" ,
137+ 			redirectURI : "https://mcp.docker.com/oauth/callback" ,
138+ 			expectError : false ,
139+ 			description : "Production mcp.docker.com should be allowed" ,
140+ 		},
141+ 		{
142+ 			name :        "evil domain" ,
143+ 			redirectURI : "https://evil.com/callback" ,
144+ 			expectError : true ,
145+ 			description : "Arbitrary domains should be blocked" ,
146+ 		},
147+ 		{
148+ 			name :        "attacker ngrok" ,
149+ 			redirectURI : "https://attacker.ngrok.io/callback" ,
150+ 			expectError : true ,
151+ 			description : "Attacker-controlled domains should be blocked" ,
152+ 		},
153+ 		{
154+ 			name :        "subdomain of docker.com" ,
155+ 			redirectURI : "https://evil.docker.com/callback" ,
156+ 			expectError : true ,
157+ 			description : "Only mcp.docker.com should be allowed, not subdomains" ,
158+ 		},
159+ 		{
160+ 			name :        "invalid URL" ,
161+ 			redirectURI : "not-a-valid-url" ,
162+ 			expectError : true ,
163+ 			description : "Invalid URL format should be rejected" ,
164+ 		},
165+ 	}
166+ 
167+ 	for  _ , tt  :=  range  tests  {
168+ 		t .Run (tt .name , func (t  * testing.T ) {
169+ 			err  :=  isValidRedirectURI (tt .redirectURI )
170+ 			if  tt .expectError  &&  err  ==  nil  {
171+ 				t .Errorf ("Expected error for %q (%s)" , tt .redirectURI , tt .description )
172+ 			}
173+ 			if  ! tt .expectError  &&  err  !=  nil  {
174+ 				t .Errorf ("Unexpected error for %q: %v (%s)" , tt .redirectURI , err , tt .description )
175+ 			}
176+ 		})
177+ 	}
178+ }
0 commit comments