diff --git a/Documentation/rest-api-accounts.txt b/Documentation/rest-api-accounts.txt index c034cf0429..98ea303b2a 100644 --- a/Documentation/rest-api-accounts.txt +++ b/Documentation/rest-api-accounts.txt @@ -420,6 +420,43 @@ Deletes the HTTP password of an account. HTTP/1.1 204 No Content ---- +[[get-oauth-token]] +=== Get OAuth Access Token +-- +'GET /accounts/link:#account-id[\{account-id\}]/oauthtoken' +-- + +Returns a previously obtained OAuth access token. + +.Request +---- + GET /accounts/self/oauthtoken HTTP/1.1 +---- + +As a response, an link:#oauth-token-info[OAuthTokenInfo] entity is returned +that describes the OAuth access token. + +.Response +---- + HTTP/1.1 200 OK + Content-Disposition: attachment + Content-Type: application/json; charset=UTF-8 + + )]}' + { + "username": "johndow", + "resource_host": "gerrit.example.org", + "access_token": "eyJhbGciOiJSUzI1NiJ9.eyJqdGkiOi", + "provider_id": "oauth-plugin:oauth-provider", + "expires_at": "922337203775807", + "type": "bearer" + } +---- + +If there is no token available, or the token has already expired, +"`404 Not Found`" is returned as response. Requests to obtain an access +token of another user are rejected with "`403 Forbidden`". + [[list-account-emails]] === List Account Emails -- @@ -2214,6 +2251,22 @@ If empty or not set and `generate` is false or not set, the HTTP password is deleted. |============================ +[[oauth-token-info]] +=== OAuthTokenInfo +The `OAuthTokenInfo` entity contains information about an OAuth access token. + +[options="header",cols="1,^1,5"] +|======================== +|Field Name ||Description +|`username` ||The owner of the OAuth access token. +|`resource_host` ||The host of the Gerrit instance. +|`access_token` ||The actual token value. +|`provider_id` |optional| +The identifier of the OAuth provider in the form `plugin-name:provider-name`. +|`expires_at` |optional|Time of expiration of this token in milliseconds. +|`type` ||The type of the OAuth access token, always `bearer`. +|======================== + [[preferences-info]] === PreferencesInfo The `PreferencesInfo` entity contains information about a user's preferences. diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/PageLinks.java b/gerrit-common/src/main/java/com/google/gerrit/common/PageLinks.java index 3957a30bf2..ca3e6eab5b 100644 --- a/gerrit-common/src/main/java/com/google/gerrit/common/PageLinks.java +++ b/gerrit-common/src/main/java/com/google/gerrit/common/PageLinks.java @@ -29,6 +29,7 @@ public class PageLinks { public static final String SETTINGS_SSHKEYS = "/settings/ssh-keys"; public static final String SETTINGS_GPGKEYS = "/settings/gpg-keys"; public static final String SETTINGS_HTTP_PASSWORD = "/settings/http-password"; + public static final String SETTINGS_OAUTH_TOKEN = "/settings/oauth-token"; public static final String SETTINGS_WEBIDENT = "/settings/web-identities"; public static final String SETTINGS_MYGROUPS = "/settings/group-memberships"; public static final String SETTINGS_AGREEMENTS = "/settings/agreements"; diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/auth/oauth/OAuthToken.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/auth/oauth/OAuthToken.java index 99b2cfa8ea..788f4201ce 100644 --- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/auth/oauth/OAuthToken.java +++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/auth/oauth/OAuthToken.java @@ -31,16 +31,23 @@ public class OAuthToken implements Serializable { */ private final long expiresAt; + /** + * The identifier of the OAuth provider that issued this token + * in the form "plugin-name:provider-name", or {@code null}. + */ + private final String providerId; + public OAuthToken(String token, String secret, String raw) { - this(token, secret, raw, Long.MAX_VALUE); + this(token, secret, raw, Long.MAX_VALUE, null); } public OAuthToken(String token, String secret, String raw, - long expiresAt) { + long expiresAt, String providerId) { this.token = token; this.secret = secret; this.raw = raw; this.expiresAt = expiresAt; + this.providerId = providerId; } public String getToken() { @@ -62,4 +69,8 @@ public class OAuthToken implements Serializable { public boolean isExpired() { return System.currentTimeMillis() > expiresAt; } + + public String getProviderId() { + return providerId; + } } diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/OAuthTokenInfo.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/OAuthTokenInfo.java new file mode 100644 index 0000000000..08fd130286 --- /dev/null +++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/OAuthTokenInfo.java @@ -0,0 +1,31 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.client.info; + +import com.google.gwt.core.client.JavaScriptObject; + + +public class OAuthTokenInfo extends JavaScriptObject { + + protected OAuthTokenInfo() { + } + + public final native String username() /*-{ return this.username; }-*/; + public final native String resourceHost() /*-{ return this.resource_host; }-*/; + public final native String accessToken() /*-{ return this.access_token; }-*/; + public final native String providerId() /*-{ return this.provider_id; }-*/; + public final native String expiresAt() /*-{ return this.expires_at; }-*/; + public final native String type() /*-{ return this.type; }-*/; +} diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java index 57e79d11ad..ad3489a133 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java @@ -33,6 +33,7 @@ import static com.google.gerrit.common.PageLinks.SETTINGS_EDIT_PREFERENCES; import static com.google.gerrit.common.PageLinks.SETTINGS_EXTENSION; import static com.google.gerrit.common.PageLinks.SETTINGS_GPGKEYS; import static com.google.gerrit.common.PageLinks.SETTINGS_HTTP_PASSWORD; +import static com.google.gerrit.common.PageLinks.SETTINGS_OAUTH_TOKEN; import static com.google.gerrit.common.PageLinks.SETTINGS_MYGROUPS; import static com.google.gerrit.common.PageLinks.SETTINGS_NEW_AGREEMENT; import static com.google.gerrit.common.PageLinks.SETTINGS_PREFERENCES; @@ -48,6 +49,7 @@ import com.google.gerrit.client.account.MyEditPreferencesScreen; import com.google.gerrit.client.account.MyGpgKeysScreen; import com.google.gerrit.client.account.MyGroupsScreen; import com.google.gerrit.client.account.MyIdentitiesScreen; +import com.google.gerrit.client.account.MyOAuthTokenScreen; import com.google.gerrit.client.account.MyPasswordScreen; import com.google.gerrit.client.account.MyPreferencesScreen; import com.google.gerrit.client.account.MyProfileScreen; @@ -568,6 +570,12 @@ public class Dispatcher { return new MyPasswordScreen(); } + if (matchExact(SETTINGS_OAUTH_TOKEN, token) + && Gerrit.info().auth().isOAuth() + && Gerrit.info().auth().isGitBasicAuth()) { + return new MyOAuthTokenScreen(); + } + if (matchExact(MY_GROUPS, token) || matchExact(SETTINGS_MYGROUPS, token)) { return new MyGroupsScreen(); diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java index 980f27d29b..32e30d4d42 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java @@ -105,6 +105,14 @@ public interface GerritCss extends CssResource { String menuScreenMenuBar(); String needsReview(); String negscore(); + String oauthExpires(); + String oauthInfoBlock(); + String oauthPanel(); + String oauthPanelCookieEntry(); + String oauthPanelCookieHeading(); + String oauthPanelNetRCEntry(); + String oauthPanelNetRCHeading(); + String oauthToken(); String pagingLink(); String patchSetActions(); String pluginProjectConfigInheritedValue(); diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.java index 549923c59f..a084612ff0 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.java @@ -57,6 +57,7 @@ public interface AccountConstants extends Constants { String tabGpgKeys(); String tabHttpAccess(); String tabMyGroups(); + String tabOAuthToken(); String tabPreferences(); String tabSshKeys(); String tabWatchedProjects(); @@ -81,6 +82,12 @@ public interface AccountConstants extends Constants { String invalidUserName(); String invalidUserEmail(); + String labelOAuthToken(); + String labelOAuthExpires(); + String labelOAuthNetRCEntry(); + String labelOAuthGitCookie(); + String labelOAuthExpired(); + String sshKeyInvalid(); String sshKeyAlgorithm(); String sshKeyKey(); diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.properties index 0ed262066c..8cd8dc7cb8 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.properties +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.properties @@ -44,6 +44,7 @@ tabDiffPreferences = Diff Preferences tabEditPreferences = Edit Preferences tabGpgKeys = GPG Public Keys tabHttpAccess = HTTP Password +tabOAuthToken = OAuth Token tabMyGroups = Groups tabPreferences = Preferences tabSshKeys = SSH Public Keys @@ -68,6 +69,13 @@ linkEditFullName = Edit linkReloadContact = Reload invalidUserName = Username must contain only letters, numbers, _, - or . invalidUserEmail = Email format is wrong. + +labelOAuthToken = Access Token +labelOAuthExpires = Expires +labelOAuthNetRCEntry = Entry for ~/.netrc +labelOAuthGitCookie = Entry for ~/.gitcookies +labelOAuthExpired = To obtain an access token please sign out and sign in again. + sshKeyInvalid = Invalid Key sshKeyAlgorithm = Algorithm sshKeyKey = Key diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyOAuthTokenScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyOAuthTokenScreen.java new file mode 100644 index 0000000000..a4c92fee17 --- /dev/null +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyOAuthTokenScreen.java @@ -0,0 +1,197 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.client.account; + +import com.google.gerrit.client.Gerrit; +import com.google.gerrit.client.info.GeneralPreferences; +import com.google.gerrit.client.info.OAuthTokenInfo; +import com.google.gerrit.client.rpc.GerritCallback; +import com.google.gerrit.client.rpc.ScreenLoadCallback; +import com.google.gwt.i18n.client.DateTimeFormat; +import com.google.gwt.i18n.client.LocaleInfo; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.HTMLTable.CellFormatter; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.Widget; +import com.google.gwtexpui.clippy.client.CopyableLabel; + +import java.util.Date; + +public class MyOAuthTokenScreen extends SettingsScreen { + private CopyableLabel tokenLabel; + private Label expiresLabel; + private Label expiredNote; + private CopyableLabel netrcValue; + private CopyableLabel cookieValue; + private FlowPanel flow; + private Grid grid; + + @Override + protected void onInitUI() { + super.onInitUI(); + + tokenLabel = new CopyableLabel(""); + tokenLabel.addStyleName(Gerrit.RESOURCES.css().oauthToken()); + + expiresLabel = new Label(""); + expiresLabel.addStyleName(Gerrit.RESOURCES.css().oauthExpires()); + + grid = new Grid(2, 2); + grid.setStyleName(Gerrit.RESOURCES.css().infoBlock()); + grid.addStyleName(Gerrit.RESOURCES.css().oauthInfoBlock()); + add(grid); + + expiredNote = new Label(Util.C.labelOAuthExpired()); + expiredNote.setVisible(false); + add(expiredNote); + + row(grid, 0, Util.C.labelOAuthToken(), tokenLabel); + row(grid, 1, Util.C.labelOAuthExpires(), expiresLabel); + + CellFormatter fmt = grid.getCellFormatter(); + fmt.addStyleName(0, 0, Gerrit.RESOURCES.css().topmost()); + fmt.addStyleName(0, 1, Gerrit.RESOURCES.css().topmost()); + fmt.addStyleName(1, 0, Gerrit.RESOURCES.css().bottomheader()); + + flow = new FlowPanel(); + flow.setStyleName(Gerrit.RESOURCES.css().oauthPanel()); + add(flow); + + Label netrcLabel = new Label(Util.C.labelOAuthNetRCEntry()); + netrcLabel.setStyleName(Gerrit.RESOURCES.css().oauthPanelNetRCHeading()); + flow.add(netrcLabel); + netrcValue= new CopyableLabel(""); + netrcValue.setStyleName(Gerrit.RESOURCES.css().oauthPanelNetRCEntry()); + flow.add(netrcValue); + + Label cookieLabel = new Label(Util.C.labelOAuthGitCookie()); + cookieLabel.setStyleName(Gerrit.RESOURCES.css().oauthPanelCookieHeading()); + flow.add(cookieLabel); + cookieValue = new CopyableLabel(""); + cookieValue.setStyleName(Gerrit.RESOURCES.css().oauthPanelCookieEntry()); + flow.add(cookieValue); + } + + private void row(Grid grid, int row, String name, Widget field) { + final CellFormatter fmt = grid.getCellFormatter(); + if (LocaleInfo.getCurrentLocale().isRTL()) { + grid.setText(row, 1, name); + grid.setWidget(row, 0, field); + fmt.addStyleName(row, 1, Gerrit.RESOURCES.css().header()); + } else { + grid.setText(row, 0, name); + grid.setWidget(row, 1, field); + fmt.addStyleName(row, 0, Gerrit.RESOURCES.css().header()); + } + } + + @Override + protected void onLoad() { + super.onLoad(); + AccountApi.self().view("preferences") + .get(new ScreenLoadCallback(this) { + @Override + protected void preDisplay(GeneralPreferences prefs) { + display(prefs); + } + }); + } + + private void display(final GeneralPreferences prefs) { + AccountApi.self().view("oauthtoken") + .get(new GerritCallback() { + @Override + public void onSuccess(OAuthTokenInfo tokenInfo) { + tokenLabel.setText(tokenInfo.accessToken()); + expiresLabel.setText(getExpiresAt(tokenInfo, prefs)); + netrcValue.setText(getNetRC(tokenInfo)); + cookieValue.setText(getCookie(tokenInfo)); + flow.setVisible(true); + expiredNote.setVisible(false); + } + @Override + public void onFailure(Throwable caught) { + if (isNoSuchEntity(caught) || isSigninFailure(caught)) { + tokenLabel.setText(""); + expiresLabel.setText(""); + netrcValue.setText(""); + cookieValue.setText(""); + flow.setVisible(false); + expiredNote.setVisible(true); + } else { + showFailure(caught); + } + } + }); + } + + private static long getExpiresAt(OAuthTokenInfo tokenInfo) { + if (tokenInfo.expiresAt() == null) { + return Long.MAX_VALUE; + } + long expiresAt; + try { + expiresAt = Long.parseLong(tokenInfo.expiresAt()); + } catch (NumberFormatException e) { + return Long.MAX_VALUE; + } + return expiresAt; + } + + private static long getExpiresAtSeconds(OAuthTokenInfo tokenInfo) { + return getExpiresAt(tokenInfo) / 1000L; + } + + private static String getExpiresAt(OAuthTokenInfo tokenInfo, + GeneralPreferences prefs) { + long expiresAt = getExpiresAt(tokenInfo); + if (expiresAt == Long.MAX_VALUE) { + return ""; + } + String dateFormat = prefs.dateFormat().getLongFormat(); + String timeFormat = prefs.timeFormat().getFormat(); + DateTimeFormat formatter = DateTimeFormat.getFormat( + dateFormat + " " + timeFormat); + return formatter.format(new Date(expiresAt)); + } + + private static String getNetRC(OAuthTokenInfo accessTokenInfo) { + StringBuilder sb = new StringBuilder(); + sb.append("machine "); + sb.append(accessTokenInfo.resourceHost()); + sb.append(" login "); + sb.append(accessTokenInfo.username()); + sb.append(" password "); + sb.append(accessTokenInfo.accessToken()); + return sb.toString(); + } + + private static String getCookie(OAuthTokenInfo accessTokenInfo) { + StringBuilder sb = new StringBuilder(); + sb.append(accessTokenInfo.resourceHost()); + sb.append("\tFALSE\t/\tTRUE\t"); + sb.append(getExpiresAtSeconds(accessTokenInfo)); + sb.append("\tgit-"); + sb.append(accessTokenInfo.username()); + sb.append('\t'); + sb.append(accessTokenInfo.accessToken()); + if (accessTokenInfo.providerId() != null) { + sb.append('@').append(accessTokenInfo.providerId()); + } + return sb.toString(); + } + +} diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/SettingsScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/SettingsScreen.java index 405ef68e4a..ee7407e6ef 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/SettingsScreen.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/SettingsScreen.java @@ -47,6 +47,10 @@ public abstract class SettingsScreen extends MenuScreen { if (Gerrit.info().auth().isHttpPasswordSettingsEnabled()) { linkByGerrit(Util.C.tabHttpAccess(), PageLinks.SETTINGS_HTTP_PASSWORD); } + if (Gerrit.info().auth().isOAuth() + && Gerrit.info().auth().isGitBasicAuth()) { + linkByGerrit(Util.C.tabOAuthToken(), PageLinks.SETTINGS_OAUTH_TOKEN); + } if (Gerrit.info().gerrit().editGpgKeys()) { linkByGerrit(Util.C.tabGpgKeys(), PageLinks.SETTINGS_GPGKEYS); } diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css index 8653a95b48..419067299f 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css @@ -828,6 +828,70 @@ a:hover.downloadLink { margin-bottom: 10px; } +.oauthInfoBlock { + margin-bottom: 10px; +} +.oauthToken { + font-family: monospace; + font-size: small; + width: 40em; +} +.oauthToken span { + white-space: nowrap; + display: inline-block; + overflow: hidden; + text-overflow: ellipsis; + width: 38em; +} +.oauthExpires { + font-family: monospace; + font-size: small; + width: 40em; +} +.oauthPanel { + margin-top: 10px; + border: 1px solid trimColor; + padding: 5px 5px 5px 5px; +} +.oauthPanelNetRCHeading { + margin-top: 5px; + margin-left: 1em; + white-space: nowrap; +} +.oauthPanelNetRCEntry { + margin-top: 5px; + margin-left: 2em; + font-family: monospace; + font-size: small; + width: 80em; +} +.oauthPanelNetRCEntry span { + white-space: nowrap; + display: inline-block; + overflow: hidden; + text-overflow: ellipsis; + width: 78em; +} +.oauthPanelCookieHeading { + margin-top: 15px; + margin-left: 1em; + white-space: nowrap; +} +.oauthPanelCookieEntry { + margin-top: 5px; + margin-left: 2em; + font-family: monospace; + font-size: small; + width: 80em; +} +.oauthPanelCookieEntry span { + white-space: nowrap; + display: inline-block; + overflow: hidden; + text-overflow: ellipsis; + width: 78em; +} + /** CommentedActionDialog **/ .commentedActionDialog .gwt-DisclosurePanel .header td { diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetOAuthToken.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetOAuthToken.java new file mode 100644 index 0000000000..b6ba3bca10 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetOAuthToken.java @@ -0,0 +1,90 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.server.account; + +import com.google.gerrit.extensions.auth.oauth.OAuthToken; +import com.google.gerrit.extensions.restapi.AuthException; +import com.google.gerrit.extensions.restapi.ResourceNotFoundException; +import com.google.gerrit.extensions.restapi.RestReadView; +import com.google.gerrit.server.CurrentUser; +import com.google.gerrit.server.auth.oauth.OAuthTokenCache; +import com.google.gerrit.server.config.CanonicalWebUrl; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; + +import java.net.URI; +import java.net.URISyntaxException; + +@Singleton +class GetOAuthToken implements RestReadView{ + + private static final String BEARER_TYPE = "bearer"; + + private final Provider self; + private final OAuthTokenCache tokenCache; + private final String hostName; + + @Inject + GetOAuthToken(Provider self, + OAuthTokenCache tokenCache, + @CanonicalWebUrl Provider urlProvider) { + this.self = self; + this.tokenCache = tokenCache; + this.hostName = getHostName(urlProvider.get()); + } + + @Override + public OAuthTokenInfo apply(AccountResource rsrc) throws AuthException, + ResourceNotFoundException { + if (self.get() != rsrc.getUser()) { + throw new AuthException("not allowed to get access token"); + } + String username = rsrc.getUser().getAccount().getUserName(); + if (username == null) { + throw new ResourceNotFoundException(); + } + OAuthToken accessToken = tokenCache.get(username); + if (accessToken == null) { + throw new ResourceNotFoundException(); + } + OAuthTokenInfo accessTokenInfo = new OAuthTokenInfo(); + accessTokenInfo.username = username; + accessTokenInfo.resourceHost = hostName; + accessTokenInfo.accessToken = accessToken.getToken(); + accessTokenInfo.providerId = accessToken.getProviderId(); + accessTokenInfo.expiresAt = Long.toString(accessToken.getExpiresAt()); + accessTokenInfo.type = BEARER_TYPE; + return accessTokenInfo; + } + + private static String getHostName(String canonicalWebUrl) { + try { + return new URI(canonicalWebUrl).getHost(); + } catch (URISyntaxException e) { + return null; + } + } + + public static class OAuthTokenInfo { + public String username; + public String resourceHost; + public String accessToken; + public String providerId; + public String expiresAt; + public String type; + } + +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/Module.java index 52e9d4c8c2..9604322cf4 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/account/Module.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/Module.java @@ -66,6 +66,8 @@ public class Module extends RestApiModule { get(SSH_KEY_KIND).to(GetSshKey.class); delete(SSH_KEY_KIND).to(DeleteSshKey.class); + get(ACCOUNT_KIND, "oauthtoken").to(GetOAuthToken.class); + get(ACCOUNT_KIND, "avatar").to(GetAvatar.class); get(ACCOUNT_KIND, "avatar.change.url").to(GetAvatarChangeUrl.class); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GetServerInfo.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetServerInfo.java index 6c774cf7a4..b30616cefc 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GetServerInfo.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetServerInfo.java @@ -128,6 +128,7 @@ public class GetServerInfo implements RestReadView { info.useContributorAgreements = toBoolean(cfg.isUseContributorAgreements()); info.editableAccountFields = new ArrayList<>(realm.getEditableFields()); info.switchAccountUrl = cfg.getSwitchAccountUrl(); + info.isGitBasicAuth = toBoolean(cfg.isGitBasicAuth()); switch (info.authType) { case LDAP: @@ -135,7 +136,6 @@ public class GetServerInfo implements RestReadView { info.registerUrl = cfg.getRegisterUrl(); info.registerText = cfg.getRegisterText(); info.editFullNameUrl = cfg.getEditFullNameUrl(); - info.isGitBasicAuth = toBoolean(cfg.isGitBasicAuth()); break; case CUSTOM_EXTENSION: