Skip to content

Commit c837a54

Browse files
committed
utils: Add password authentication for (non-proxy) servers
For now, only support authentication stored in .netrc files [1] in plain text as that is also support by the Git CLI which still gets called in Git.kt. Resolves #2580. [1] https://www.gnu.org/software/inetutils/manual/html_node/The-_002enetrc-file.html Signed-off-by: Sebastian Schuberth <sebastian.schuberth@bosch.io>
1 parent bffdbd9 commit c837a54

File tree

2 files changed

+133
-6
lines changed

2 files changed

+133
-6
lines changed

utils/src/main/kotlin/OrtAuthenticator.kt

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,54 @@ class OrtAuthenticator(private val original: Authenticator? = null) : Authentica
7474
}
7575

7676
override fun getPasswordAuthentication(): PasswordAuthentication? {
77-
if (requestorType == RequestorType.PROXY) {
78-
val proxySelector = ProxySelector.getDefault()
79-
if (proxySelector is OrtProxySelector) {
80-
val type = requestingProtocol.toProxyType() ?: return null
81-
val proxy = Proxy(type, InetSocketAddress(requestingHost, requestingPort))
82-
return proxySelector.getProxyAuthentication(proxy)
77+
when (requestorType) {
78+
RequestorType.PROXY -> {
79+
val proxySelector = ProxySelector.getDefault()
80+
if (proxySelector is OrtProxySelector) {
81+
val type = requestingProtocol.toProxyType() ?: return null
82+
val proxy = Proxy(type, InetSocketAddress(requestingHost, requestingPort))
83+
return proxySelector.getProxyAuthentication(proxy)
84+
}
85+
}
86+
87+
RequestorType.SERVER -> {
88+
val netrcFile = getUserHomeDirectory().resolve(".netrc")
89+
if (netrcFile.isFile) {
90+
getNetrcAuthentication(netrcFile.readText(), requestingHost)?.let { return it }
91+
}
92+
93+
// TODO: Add support for .authinfo files (which use the same syntax as .netrc files) once Git.kt does
94+
// not call the Git CLI anymore which only suuports .netrc files.
8395
}
96+
97+
null -> log.warn { "No requestor type set for password authentication." }
8498
}
8599

86100
return super.getPasswordAuthentication()
87101
}
88102
}
103+
104+
fun getNetrcAuthentication(contents: String, machine: String): PasswordAuthentication? {
105+
val lines = contents.lines().mapNotNull { line ->
106+
line.trim().takeUnless { it.startsWith('#') }
107+
}
108+
109+
val iterator = lines.joinToString(" ").split(Regex("\\s")).iterator()
110+
111+
var machineFound = false
112+
var login: String? = null
113+
var password: String? = null
114+
115+
while (iterator.hasNext()) {
116+
when (iterator.next()) {
117+
"machine" -> machineFound = iterator.hasNext() && iterator.next() == machine
118+
"login" -> login = if (machineFound && iterator.hasNext()) iterator.next() else null
119+
"password" -> password = if (machineFound && iterator.hasNext()) iterator.next() else null
120+
"default" -> machineFound = true
121+
}
122+
123+
if (login != null && password != null) return PasswordAuthentication(login, password.toCharArray())
124+
}
125+
126+
return null
127+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright (C) 2020 Bosch.IO GmbH
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
* License-Filename: LICENSE
18+
*/
19+
20+
package org.ossreviewtoolkit.utils
21+
22+
import io.kotest.core.spec.style.WordSpec
23+
import io.kotest.matchers.shouldBe
24+
import io.kotest.matchers.shouldNotBe
25+
26+
class OrtAuthenticatorTest : WordSpec({
27+
"getNetrcAuthentication()" should {
28+
"correctly parse single-line contents" {
29+
val authentication = getNetrcAuthentication("""
30+
machine github.com login foo password bar
31+
""".trimIndent(), "github.com")
32+
33+
authentication shouldNotBe null
34+
authentication!!.userName shouldBe "foo"
35+
authentication.password shouldBe "bar".toCharArray()
36+
}
37+
38+
"correctly parse multi-line contents" {
39+
val authentication = getNetrcAuthentication("""
40+
machine gitlab.com
41+
login foo
42+
password bar
43+
""".trimIndent(), "gitlab.com")
44+
45+
authentication shouldNotBe null
46+
authentication!!.userName shouldBe "foo"
47+
authentication.password shouldBe "bar".toCharArray()
48+
}
49+
50+
"recognize the default machine" {
51+
val authentication = getNetrcAuthentication("""
52+
machine github.com
53+
login git
54+
password hub
55+
default login foo password bar
56+
""".trimIndent(), "gitlab.com")
57+
58+
authentication shouldNotBe null
59+
authentication!!.userName shouldBe "foo"
60+
authentication.password shouldBe "bar".toCharArray()
61+
}
62+
63+
"ignore superfluous statements" {
64+
val authentication = getNetrcAuthentication("""
65+
machine "# A funky way to add comments."
66+
login funkyLogin
67+
password funkyPassword
68+
machine bitbucket.com
69+
# This is a port.
70+
port 433
71+
password bar
72+
login foo
73+
""".trimIndent(), "bitbucket.com")
74+
75+
authentication shouldNotBe null
76+
authentication!!.userName shouldBe "foo"
77+
authentication.password shouldBe "bar".toCharArray()
78+
}
79+
80+
"ignore irrelavant machines" {
81+
val authentication = getNetrcAuthentication("""
82+
machine bitbucket.com login foo password bar
83+
""".trimIndent(), "github.com")
84+
85+
authentication shouldBe null
86+
}
87+
}
88+
})

0 commit comments

Comments
 (0)