Skip to content

Commit dd0b1a1

Browse files
authored
Merge pull request #17591 from iterate-ch/feature/GH-17590
Set username from standard claim.
2 parents 82f3caf + 0c6d654 commit dd0b1a1

File tree

8 files changed

+58
-52
lines changed

8 files changed

+58
-52
lines changed

core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import org.apache.logging.log4j.Logger;
2525

2626
import java.net.URI;
27+
import java.util.HashSet;
28+
import java.util.Set;
2729

2830
public abstract class DefaultHostPasswordStore implements HostPasswordStore {
2931
private static final Logger log = LogManager.getLogger(DefaultHostPasswordStore.class);
@@ -132,8 +134,7 @@ public String findPrivateKeyPassphrase(final Host bookmark) {
132134
@Override
133135
public OAuthTokens findOAuthTokens(final Host bookmark) {
134136
log.info("Fetching OAuth tokens from keychain for {}", bookmark);
135-
final String[] descriptors = getOAuthPrefix(bookmark);
136-
for(String prefix : descriptors) {
137+
for(String prefix : getOAuthPrefix(bookmark)) {
137138
log.debug("Search with prefix {}", prefix);
138139
final String hostname = getOAuthHostname(bookmark);
139140
log.debug("Search with hostname {}", hostname);
@@ -185,17 +186,27 @@ protected static int getOAuthPort(final Host bookmark) {
185186
return getOAuthScheme(bookmark).getPort();
186187
}
187188

188-
protected static String[] getOAuthPrefix(final Host bookmark) {
189+
protected static Set<String> getOAuthPrefix(final Host bookmark) {
190+
final Set<String> prefix = new HashSet<>();
189191
if(StringUtils.isNotBlank(bookmark.getCredentials().getUsername())) {
190-
return new String[]{
191-
String.format("%s (%s)", bookmark.getProtocol().getOAuthClientId(), bookmark.getCredentials().getUsername()),
192-
String.format("%s (%s)", bookmark.getProtocol().getDescription(), bookmark.getCredentials().getUsername())
193-
};
192+
if(StringUtils.isNotBlank(bookmark.getProtocol().getOAuthClientId())) {
193+
prefix.add(String.format("%s (%s)", bookmark.getProtocol().getOAuthClientId(), bookmark.getCredentials().getUsername()));
194+
}
195+
if(StringUtils.isNotBlank(bookmark.getProperty(Profile.OAUTH_CLIENT_ID_KEY))) {
196+
prefix.add(String.format("%s (%s)", bookmark.getProperty(Profile.OAUTH_CLIENT_ID_KEY), bookmark.getCredentials().getUsername()));
197+
}
198+
prefix.add(String.format("%s (%s)", bookmark.getProtocol().getDescription(), bookmark.getCredentials().getUsername()));
199+
}
200+
else {
201+
if(StringUtils.isNotBlank(bookmark.getProtocol().getOAuthClientId())) {
202+
prefix.add(bookmark.getProtocol().getOAuthClientId());
203+
}
204+
if(StringUtils.isNotBlank(bookmark.getProperty(Profile.OAUTH_CLIENT_ID_KEY))) {
205+
prefix.add(bookmark.getProperty(Profile.OAUTH_CLIENT_ID_KEY));
206+
}
207+
prefix.add(bookmark.getProtocol().getDescription());
194208
}
195-
return new String[]{
196-
bookmark.getProtocol().getOAuthClientId(),
197-
bookmark.getProtocol().getDescription()
198-
};
209+
return prefix;
199210
}
200211

201212
@Override
@@ -227,8 +238,7 @@ public void save(final Host bookmark) throws LocalAccessDeniedException {
227238
credentials.getToken());
228239
}
229240
if(credentials.isOAuthAuthentication()) {
230-
final String[] descriptors = getOAuthPrefix(bookmark);
231-
for(String prefix : descriptors) {
241+
for(String prefix : getOAuthPrefix(bookmark)) {
232242
if(StringUtils.isNotBlank(credentials.getOauth().getAccessToken())) {
233243
this.addPassword(getOAuthScheme(bookmark),
234244
getOAuthPort(bookmark), getOAuthHostname(bookmark),
@@ -273,8 +283,7 @@ public void delete(final Host bookmark) throws LocalAccessDeniedException {
273283
protocol.getTokenPlaceholder() : String.format("%s (%s)", protocol.getTokenPlaceholder(), credentials.getUsername()));
274284
}
275285
if(protocol.isOAuthConfigurable()) {
276-
final String[] descriptors = getOAuthPrefix(bookmark);
277-
for(String prefix : descriptors) {
286+
for(String prefix : getOAuthPrefix(bookmark)) {
278287
if(StringUtils.isNotBlank(credentials.getOauth().getAccessToken())) {
279288
this.deletePassword(getOAuthScheme(bookmark), getOAuthPort(bookmark), getOAuthHostname(bookmark),
280289
String.format("%s OAuth2 Access Token", prefix));

core/src/test/java/ch/cyberduck/core/DefaultHostPasswordStoreTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public String getOAuthClientSecret() {
3838
public String getOAuthRedirectUrl() {
3939
return "x-cyberduck-action:oauth";
4040
}
41-
}));
41+
})).toArray(new String[0]);
4242
assertEquals("clientid", prefix[0]);
4343
assertEquals("Test", prefix[1]);
4444
}
@@ -60,7 +60,7 @@ public String getOAuthClientSecret() {
6060
public String getOAuthRedirectUrl() {
6161
return "x-cyberduck-action:oauth";
6262
}
63-
}).withCredentials(new Credentials("user")));
63+
}).withCredentials(new Credentials("user"))).toArray(new String[0]);
6464
assertEquals("clientid (user)", prefix[0]);
6565
assertEquals("Test (user)", prefix[1]);
6666
}

oauth/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,9 @@
5050
<groupId>com.google.http-client</groupId>
5151
<artifactId>google-http-client-gson</artifactId>
5252
</dependency>
53+
<dependency>
54+
<groupId>com.auth0</groupId>
55+
<artifactId>java-jwt</artifactId>
56+
</dependency>
5357
</dependencies>
5458
</project>

oauth/src/main/java/ch/cyberduck/core/oauth/BrowserOAuth2AuthorizationCodeProvider.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,10 @@ protected void open(final String authorizationCodeRequestUrl) throws LoginCancel
4242
@Override
4343
public String prompt(final Host bookmark, final LoginCallback prompt, final String authorizationCodeUrl, final String redirectUri, final String state) throws BackgroundException {
4444
log.debug("Evaluate redirect URI {}", redirectUri);
45-
if(StringUtils.endsWith(URIEncoder.decode(redirectUri), ":oauth")) {
46-
return new CustomSchemeHandlerOAuth2AuthorizationCodeProvider().prompt(
47-
bookmark, prompt, authorizationCodeUrl, redirectUri, state);
48-
}
49-
if(StringUtils.contains(redirectUri, "://oauth")) {
50-
return new CustomSchemeHandlerOAuth2AuthorizationCodeProvider().prompt(
51-
bookmark, prompt, authorizationCodeUrl, redirectUri, state);
45+
if(StringUtils.endsWith(URIEncoder.decode(redirectUri), ":oauth") || StringUtils.contains(redirectUri, "://oauth")) {
46+
return new CustomSchemeHandlerOAuth2AuthorizationCodeProvider().prompt(bookmark, prompt, authorizationCodeUrl, redirectUri, state);
5247
}
5348
log.debug("Prompt for authentication code for state {}", state);
54-
return new PromptOAuth2AuthorizationCodeProvider().prompt(
55-
bookmark, prompt, authorizationCodeUrl, redirectUri, state);
49+
return new PromptOAuth2AuthorizationCodeProvider().prompt(bookmark, prompt, authorizationCodeUrl, redirectUri, state);
5650
}
5751
}

oauth/src/main/java/ch/cyberduck/core/oauth/OAuth2AuthorizationCodeProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,5 @@ public interface OAuth2AuthorizationCodeProvider {
3131
* @param state Custom state
3232
* @return Authentication code
3333
*/
34-
String prompt(Host bookmark, final LoginCallback prompt, String authorizationCodeRequestUrl, String redirectUri, final String state) throws BackgroundException;
34+
String prompt(Host bookmark, LoginCallback prompt, String authorizationCodeRequestUrl, String redirectUri, String state) throws BackgroundException;
3535
}

oauth/src/main/java/ch/cyberduck/core/oauth/OAuth2AuthorizationService.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
import java.util.List;
3636
import java.util.Map;
3737

38+
import com.auth0.jwt.JWT;
39+
import com.auth0.jwt.exceptions.JWTDecodeException;
40+
import com.auth0.jwt.interfaces.DecodedJWT;
3841
import com.google.api.client.auth.oauth2.AuthorizationCodeFlow;
3942
import com.google.api.client.auth.oauth2.AuthorizationCodeRequestUrl;
4043
import com.google.api.client.auth.oauth2.BearerToken;
@@ -157,6 +160,27 @@ public OAuthTokens validate(final OAuthTokens saved) throws BackgroundException
157160
public OAuthTokens save(final OAuthTokens tokens) throws LocalAccessDeniedException {
158161
log.debug("Save new tokens {} for {}", tokens, host);
159162
credentials.setOauth(tokens).setSaved(new LoginOptions().save);
163+
switch(flowType) {
164+
case PasswordGrant:
165+
// Skip modifying username used for password grant
166+
break;
167+
default:
168+
try {
169+
final DecodedJWT jwt = JWT.decode(tokens.getIdToken());
170+
// Standard claims
171+
for(String claim : new String[]{"preferred_username", "email", "name", "nickname", "sub"}) {
172+
final String value = jwt.getClaim(claim).asString();
173+
if(StringUtils.isNotBlank(value)) {
174+
credentials.setUsername(value);
175+
break;
176+
}
177+
}
178+
}
179+
catch(JWTDecodeException e) {
180+
log.warn("Failure {} decoding JWT {}", e, tokens.getIdToken());
181+
}
182+
break;
183+
}
160184
if(credentials.isSaved()) {
161185
store.save(host);
162186
}

owncloud/pom.xml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,6 @@
5353
<groupId>com.fasterxml.jackson.dataformat</groupId>
5454
<artifactId>jackson-dataformat-xml</artifactId>
5555
</dependency>
56-
<dependency>
57-
<groupId>com.auth0</groupId>
58-
<artifactId>java-jwt</artifactId>
59-
</dependency>
6056
<dependency>
6157
<groupId>ch.cyberduck</groupId>
6258
<artifactId>test</artifactId>

owncloud/src/main/java/ch/cyberduck/core/owncloud/OwncloudSession.java

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,18 @@
1515
* GNU General Public License for more details.
1616
*/
1717

18-
import ch.cyberduck.core.Credentials;
1918
import ch.cyberduck.core.DefaultIOExceptionMappingService;
2019
import ch.cyberduck.core.Host;
2120
import ch.cyberduck.core.HostKeyCallback;
2221
import ch.cyberduck.core.ListService;
2322
import ch.cyberduck.core.LoginCallback;
24-
import ch.cyberduck.core.OAuthTokens;
2523
import ch.cyberduck.core.UrlProvider;
2624
import ch.cyberduck.core.dav.DAVClient;
27-
import ch.cyberduck.core.dav.DAVDirectoryFeature;
2825
import ch.cyberduck.core.dav.DAVSession;
2926
import ch.cyberduck.core.dav.DAVTouchFeature;
3027
import ch.cyberduck.core.exception.BackgroundException;
3128
import ch.cyberduck.core.features.AttributesFinder;
3229
import ch.cyberduck.core.features.Delete;
33-
import ch.cyberduck.core.features.Directory;
3430
import ch.cyberduck.core.features.Home;
3531
import ch.cyberduck.core.features.Lock;
3632
import ch.cyberduck.core.features.Read;
@@ -62,16 +58,12 @@
6258
import ch.cyberduck.core.tus.TusWriteFeature;
6359

6460
import org.apache.commons.lang3.ArrayUtils;
65-
import org.apache.commons.lang3.StringUtils;
6661
import org.apache.http.client.HttpResponseException;
6762
import org.apache.logging.log4j.LogManager;
6863
import org.apache.logging.log4j.Logger;
6964

7065
import java.io.IOException;
7166

72-
import com.auth0.jwt.JWT;
73-
import com.auth0.jwt.exceptions.JWTDecodeException;
74-
7567
import static ch.cyberduck.core.tus.TusCapabilities.TUS_VERSION;
7668

7769
public class OwncloudSession extends DAVSession {
@@ -104,19 +96,6 @@ protected DAVClient connect(final ProxyFinder proxy, final HostKeyCallback key,
10496
@Override
10597
public void login(final LoginCallback prompt, final CancelCallback cancel) throws BackgroundException {
10698
super.login(prompt, cancel);
107-
if(host.getProtocol().isOAuthConfigurable()) {
108-
final Credentials credentials = host.getCredentials();
109-
final OAuthTokens oauth = credentials.getOauth();
110-
try {
111-
final String username = JWT.decode(oauth.getIdToken()).getClaim("preferred_username").asString();
112-
if(StringUtils.isNotBlank(username)) {
113-
credentials.setUsername(username);
114-
}
115-
}
116-
catch(JWTDecodeException e) {
117-
log.warn("Failure {} decoding JWT {}", e, oauth.getIdToken());
118-
}
119-
}
12099
try {
121100
client.execute(new OcsCapabilitiesRequest(host), new OcsCapabilitiesResponseHandler(ocs));
122101
}

0 commit comments

Comments
 (0)