Skip to content

Commit 5c57ce5

Browse files
committed
iRODS: Add tests for PAM authentication
1 parent a30cb11 commit 5c57ce5

File tree

1 file changed

+190
-0
lines changed

1 file changed

+190
-0
lines changed
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
package ch.cyberduck.core.irods;
2+
3+
/*
4+
* Copyright (c) 2002-2025 iterate GmbH. All rights reserved.
5+
* https://cyberduck.io/
6+
*
7+
* This program is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*/
17+
18+
import ch.cyberduck.core.Credentials;
19+
import ch.cyberduck.core.DisabledCancelCallback;
20+
import ch.cyberduck.core.DisabledHostKeyCallback;
21+
import ch.cyberduck.core.DisabledLoginCallback;
22+
import ch.cyberduck.core.Host;
23+
import ch.cyberduck.core.Profile;
24+
import ch.cyberduck.core.ProtocolFactory;
25+
import ch.cyberduck.core.exception.BackgroundException;
26+
import ch.cyberduck.core.proxy.DisabledProxyFinder;
27+
import ch.cyberduck.core.serializer.impl.dd.ProfilePlistReader;
28+
import ch.cyberduck.core.ssl.X509TrustManager;
29+
import ch.cyberduck.test.TestcontainerTest;
30+
31+
import org.irods.irods4j.authentication.NativeAuthPlugin;
32+
import org.irods.irods4j.high_level.administration.IRODSUsers;
33+
import org.irods.irods4j.high_level.administration.IRODSZones;
34+
import org.irods.irods4j.high_level.connection.IRODSConnection;
35+
import org.irods.irods4j.high_level.connection.QualifiedUsername;
36+
import org.irods.irods4j.low_level.api.IRODSApi;
37+
import org.junit.AfterClass;
38+
import org.junit.BeforeClass;
39+
import org.junit.Test;
40+
import org.junit.experimental.categories.Category;
41+
import org.testcontainers.containers.ComposeContainer;
42+
import org.testcontainers.containers.wait.strategy.Wait;
43+
44+
import javax.net.ssl.TrustManager;
45+
import java.io.File;
46+
import java.io.IOException;
47+
import java.security.cert.CertificateException;
48+
import java.security.cert.X509Certificate;
49+
import java.util.Collections;
50+
import java.util.HashSet;
51+
import java.util.Optional;
52+
53+
import static org.junit.Assert.*;
54+
55+
@Category(TestcontainerTest.class)
56+
public class IRODSPamAuthenticationTest {
57+
58+
private static final X509TrustManager cyberduckTrustManager = new X509TrustManager() {
59+
@Override
60+
public void checkClientTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
61+
}
62+
63+
@Override
64+
public void checkServerTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
65+
}
66+
67+
@Override
68+
public X509Certificate[] getAcceptedIssuers() {
69+
return new X509Certificate[0];
70+
}
71+
72+
@Override
73+
public X509TrustManager init() throws IOException {
74+
return null;
75+
}
76+
77+
@Override
78+
public void verify(final String hostname, final X509Certificate[] certs, final String cipher) throws CertificateException {
79+
}
80+
};
81+
82+
private static final TrustManager[] irodsTrustManagers = new TrustManager[]{new javax.net.ssl.X509TrustManager() {
83+
@Override
84+
public void checkClientTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
85+
}
86+
87+
@Override
88+
public void checkServerTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
89+
}
90+
91+
@Override
92+
public X509Certificate[] getAcceptedIssuers() {
93+
return new X509Certificate[0];
94+
}
95+
}};
96+
97+
private static final ComposeContainer container = new ComposeContainer(
98+
new File(IRODSDockerComposeManager.class.getResource("/docker/docker-compose.pam.yml").getFile()))
99+
.withPull(false)
100+
.withLocalCompose(true)
101+
.withExposedService("irods-catalog-provider-1", 1347, Wait.forLogMessage(".*\"log_message\":\"Initializing delay server.\".*", 1));
102+
103+
@BeforeClass
104+
public static void start() {
105+
container.start();
106+
}
107+
108+
@AfterClass
109+
public static void shutdown() {
110+
container.stop();
111+
}
112+
113+
@Test
114+
public void testPamPasswordsContainingSpecialCharactersAreHandledCorrectly() throws Exception {
115+
final ProtocolFactory factory = new ProtocolFactory(new HashSet<>(Collections.singleton(new IRODSProtocol())));
116+
final Profile profile = new ProfilePlistReader(factory).read(
117+
this.getClass().getResourceAsStream("/iRODS_pam.cyberduckprofile"));
118+
119+
final String username = "john";
120+
final String password = "=i;r@o\\d&s";
121+
final Host host = new Host(profile, profile.getDefaultHostname(), new Credentials(username, password));
122+
final IRODSUsers.User testUser = new IRODSUsers.User(username, Optional.of(host.getRegion()));
123+
124+
IRODSApi.ConnectionOptions options = new IRODSApi.ConnectionOptions();
125+
options.clientServerNegotiation = "CS_NEG_REQUIRE";
126+
options.trustManagers = irodsTrustManagers;
127+
128+
try(IRODSConnection conn = new IRODSConnection(options)) {
129+
// Create a test user named john. We do not set a password for this user because
130+
// they are using PAM authentication.
131+
conn.connect(host.getHostname(), host.getPort(), new QualifiedUsername("rods", host.getRegion()));
132+
conn.authenticate(new NativeAuthPlugin(), "rods");
133+
IRODSUsers.addUser(conn.getRcComm(), testUser, IRODSUsers.UserType.RODSUSER, IRODSZones.ZoneType.LOCAL);
134+
135+
try {
136+
final IRODSSession session = new IRODSSession(host, cyberduckTrustManager, null);
137+
138+
assertNotNull(session.open(new DisabledProxyFinder(), new DisabledHostKeyCallback(), new DisabledLoginCallback(), new DisabledCancelCallback()));
139+
assertTrue(session.isConnected());
140+
assertNotNull(session.getClient());
141+
session.login(new DisabledLoginCallback(), new DisabledCancelCallback());
142+
143+
session.close();
144+
assertFalse(session.isConnected());
145+
}
146+
finally {
147+
IRODSUsers.removeUser(conn.getRcComm(), testUser);
148+
}
149+
}
150+
}
151+
152+
@Test
153+
public void testIncorrectPamPasswordFails() throws Exception {
154+
final ProtocolFactory factory = new ProtocolFactory(new HashSet<>(Collections.singleton(new IRODSProtocol())));
155+
final Profile profile = new ProfilePlistReader(factory).read(
156+
this.getClass().getResourceAsStream("/iRODS_pam.cyberduckprofile"));
157+
158+
final String username = "john";
159+
final String password = "incorrect";
160+
final Host host = new Host(profile, profile.getDefaultHostname(), new Credentials(username, password));
161+
final IRODSUsers.User testUser = new IRODSUsers.User(username, Optional.of(host.getRegion()));
162+
163+
IRODSApi.ConnectionOptions options = new IRODSApi.ConnectionOptions();
164+
options.clientServerNegotiation = "CS_NEG_REQUIRE";
165+
options.trustManagers = irodsTrustManagers;
166+
167+
try(IRODSConnection conn = new IRODSConnection(options)) {
168+
// Create a test user named john. We do not set a password for this user because
169+
// they are using PAM authentication.
170+
conn.connect(host.getHostname(), host.getPort(), new QualifiedUsername("rods", host.getRegion()));
171+
conn.authenticate(new NativeAuthPlugin(), "rods");
172+
IRODSUsers.addUser(conn.getRcComm(), testUser, IRODSUsers.UserType.RODSUSER, IRODSZones.ZoneType.LOCAL);
173+
174+
try {
175+
final IRODSSession session = new IRODSSession(host, cyberduckTrustManager, null);
176+
177+
assertNotNull(session.open(new DisabledProxyFinder(), new DisabledHostKeyCallback(), new DisabledLoginCallback(), new DisabledCancelCallback()));
178+
assertTrue(session.isConnected());
179+
assertNotNull(session.getClient());
180+
assertThrows(BackgroundException.class, () -> session.login(new DisabledLoginCallback(), new DisabledCancelCallback()));
181+
182+
session.close();
183+
assertFalse(session.isConnected());
184+
}
185+
finally {
186+
IRODSUsers.removeUser(conn.getRcComm(), testUser);
187+
}
188+
}
189+
}
190+
}

0 commit comments

Comments
 (0)