View Javadoc
1   /*
2    * Copyright (C) 2018, Konrad Windszus <konrad_w@gmx.de>
3    * and other copyright owners as documented in the project's IP log.
4    *
5    * This program and the accompanying materials are made available
6    * under the terms of the Eclipse Distribution License v1.0 which
7    * accompanies this distribution, is reproduced below, and is
8    * available at http://www.eclipse.org/org/documents/edl-v10.php
9    *
10   * All rights reserved.
11   *
12   * Redistribution and use in source and binary forms, with or
13   * without modification, are permitted provided that the following
14   * conditions are met:
15   *
16   * - Redistributions of source code must retain the above copyright
17   *   notice, this list of conditions and the following disclaimer.
18   *
19   * - Redistributions in binary form must reproduce the above
20   *   copyright notice, this list of conditions and the following
21   *   disclaimer in the documentation and/or other materials provided
22   *   with the distribution.
23   *
24   * - Neither the name of the Eclipse Foundation, Inc. nor the
25   *   names of its contributors may be used to endorse or promote
26   *   products derived from this software without specific prior
27   *   written permission.
28   *
29   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42   */
43  package org.eclipse.jgit.transport;
44  
45  import java.io.File;
46  import java.io.IOException;
47  import java.net.HttpCookie;
48  import java.time.Instant;
49  import java.util.Arrays;
50  import java.util.Collections;
51  import java.util.Date;
52  import java.util.LinkedHashSet;
53  import java.util.Set;
54  
55  import org.eclipse.jgit.internal.transport.http.NetscapeCookieFile;
56  import org.eclipse.jgit.lib.Config;
57  import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
58  import org.eclipse.jgit.transport.http.HttpConnection;
59  import org.eclipse.jgit.util.http.HttpCookiesMatcher;
60  import org.junit.Assert;
61  import org.junit.Before;
62  import org.junit.Test;
63  import org.mockito.ArgumentMatchers;
64  import org.mockito.Mockito;
65  
66  public class TransportHttpTest extends SampleDataRepositoryTestCase {
67  	private URIish uri;
68  	private File cookieFile;
69  
70  	@Override
71  	@Before
72  	public void setUp() throws Exception {
73  		super.setUp();
74  		uri = new URIish("https://everyones.loves.git/u/2");
75  
76  		final Config config = db.getConfig();
77  		config.setBoolean("http", null, "saveCookies", true);
78  		cookieFile = createTempFile();
79  		config.setString("http", null, "cookieFile",
80  				cookieFile.getAbsolutePath());
81  	}
82  
83  	@Test
84  	public void testMatchesCookieDomain() {
85  		Assert.assertTrue(TransportHttp.matchesCookieDomain("example.com",
86  				"example.com"));
87  		Assert.assertTrue(TransportHttp.matchesCookieDomain("Example.Com",
88  				"example.cOM"));
89  		Assert.assertTrue(TransportHttp.matchesCookieDomain(
90  				"some.subdomain.example.com", "example.com"));
91  		Assert.assertFalse(TransportHttp
92  				.matchesCookieDomain("someotherexample.com", "example.com"));
93  		Assert.assertFalse(TransportHttp.matchesCookieDomain("example.com",
94  				"example1.com"));
95  		Assert.assertFalse(TransportHttp
96  				.matchesCookieDomain("sub.sub.example.com", ".example.com"));
97  		Assert.assertTrue(TransportHttp.matchesCookieDomain("host.example.com",
98  				"example.com"));
99  		Assert.assertTrue(TransportHttp.matchesCookieDomain(
100 				"something.example.com", "something.example.com"));
101 		Assert.assertTrue(TransportHttp.matchesCookieDomain(
102 				"host.something.example.com", "something.example.com"));
103 	}
104 
105 	@Test
106 	public void testMatchesCookiePath() {
107 		Assert.assertTrue(
108 				TransportHttp.matchesCookiePath("/some/path", "/some/path"));
109 		Assert.assertTrue(TransportHttp.matchesCookiePath("/some/path/child",
110 				"/some/path"));
111 		Assert.assertTrue(TransportHttp.matchesCookiePath("/some/path/child",
112 				"/some/path/"));
113 		Assert.assertFalse(TransportHttp.matchesCookiePath("/some/pathother",
114 				"/some/path"));
115 		Assert.assertFalse(
116 				TransportHttp.matchesCookiePath("otherpath", "/some/path"));
117 	}
118 
119 	@Test
120 	public void testProcessResponseCookies() throws IOException {
121 		HttpConnection connection = Mockito.mock(HttpConnection.class);
122 		Mockito.when(
123 				connection.getHeaderFields(ArgumentMatchers.eq("Set-Cookie")))
124 				.thenReturn(Arrays.asList(
125 						"id=a3fWa; Expires=Fri, 01 Jan 2100 11:00:00 GMT; Secure; HttpOnly",
126 						"sessionid=38afes7a8; HttpOnly; Path=/"));
127 		Mockito.when(
128 				connection.getHeaderFields(ArgumentMatchers.eq("Set-Cookie2")))
129 				.thenReturn(Collections
130 						.singletonList("cookie2=some value; Max-Age=1234; Path=/"));
131 
132 		try (TransportHttp transportHttp = new TransportHttp(db, uri)) {
133 			Date creationDate = new Date();
134 			transportHttp.processResponseCookies(connection);
135 
136 			// evaluate written cookie file
137 			Set<HttpCookie> expectedCookies = new LinkedHashSet<>();
138 
139 			HttpCookie cookie = new HttpCookie("id", "a3fWa");
140 			cookie.setDomain("everyones.loves.git");
141 			cookie.setPath("/u/2/");
142 
143 			cookie.setMaxAge(
144 					(Instant.parse("2100-01-01T11:00:00.000Z").toEpochMilli()
145 							- creationDate.getTime()) / 1000);
146 			cookie.setSecure(true);
147 			cookie.setHttpOnly(true);
148 			expectedCookies.add(cookie);
149 
150 			cookie = new HttpCookie("cookie2", "some value");
151 			cookie.setDomain("everyones.loves.git");
152 			cookie.setPath("/");
153 			cookie.setMaxAge(1234);
154 			expectedCookies.add(cookie);
155 
156 			Assert.assertThat(
157 					new NetscapeCookieFile(cookieFile.toPath())
158 							.getCookies(true),
159 					HttpCookiesMatcher.containsInOrder(expectedCookies, 5));
160 		}
161 	}
162 
163 	@Test
164 	public void testProcessResponseCookiesNotPersistingWithSaveCookiesFalse()
165 			throws IOException {
166 		HttpConnection connection = Mockito.mock(HttpConnection.class);
167 		Mockito.when(
168 				connection.getHeaderFields(ArgumentMatchers.eq("Set-Cookie")))
169 				.thenReturn(Arrays.asList(
170 						"id=a3fWa; Expires=Thu, 21 Oct 2100 11:00:00 GMT; Secure; HttpOnly",
171 						"sessionid=38afes7a8; HttpOnly; Path=/"));
172 		Mockito.when(
173 				connection.getHeaderFields(ArgumentMatchers.eq("Set-Cookie2")))
174 				.thenReturn(Collections.singletonList(
175 						"cookie2=some value; Max-Age=1234; Path=/"));
176 
177 		// tweak config
178 		final Config config = db.getConfig();
179 		config.setBoolean("http", null, "saveCookies", false);
180 
181 		try (TransportHttp transportHttp = new TransportHttp(db, uri)) {
182 			transportHttp.processResponseCookies(connection);
183 
184 			// evaluate written cookie file
185 			Assert.assertFalse("Cookie file was not supposed to be written!",
186 					cookieFile.exists());
187 		}
188 	}
189 }