| // Copyright (C) 2009 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.auth.openid; |
| |
| import com.google.gerrit.client.Gerrit; |
| import com.google.gerrit.client.SignInDialog; |
| import com.google.gerrit.client.rpc.GerritCallback; |
| import com.google.gerrit.client.ui.SmallHeading; |
| import com.google.gerrit.common.auth.SignInMode; |
| import com.google.gerrit.common.auth.openid.DiscoveryResult; |
| import com.google.gerrit.common.auth.openid.OpenIdProviderPattern; |
| import com.google.gerrit.common.auth.openid.OpenIdUrls; |
| import com.google.gwt.core.client.Scheduler; |
| import com.google.gwt.core.client.Scheduler.ScheduledCommand; |
| import com.google.gwt.dom.client.FormElement; |
| import com.google.gwt.event.dom.client.ClickEvent; |
| import com.google.gwt.event.dom.client.ClickHandler; |
| import com.google.gwt.event.dom.client.KeyCodes; |
| import com.google.gwt.event.dom.client.KeyPressEvent; |
| import com.google.gwt.event.dom.client.KeyPressHandler; |
| import com.google.gwt.resources.client.ImageResource; |
| import com.google.gwt.user.client.Cookies; |
| import com.google.gwt.user.client.DOM; |
| import com.google.gwt.user.client.Window; |
| import com.google.gwt.user.client.ui.Anchor; |
| import com.google.gwt.user.client.ui.Button; |
| import com.google.gwt.user.client.ui.CheckBox; |
| import com.google.gwt.user.client.ui.FlowPanel; |
| import com.google.gwt.user.client.ui.FormPanel; |
| import com.google.gwt.user.client.ui.FormPanel.SubmitEvent; |
| import com.google.gwt.user.client.ui.FormSubmitCompleteEvent; |
| import com.google.gwt.user.client.ui.HTML; |
| import com.google.gwt.user.client.ui.Hidden; |
| import com.google.gwt.user.client.ui.Image; |
| import com.google.gwt.user.client.ui.InlineLabel; |
| import com.google.gwtexpui.globalkey.client.NpTextBox; |
| |
| import java.util.Map; |
| |
| public class OpenIdSignInDialog extends SignInDialog implements |
| FormPanel.SubmitHandler { |
| static { |
| OpenIdResources.I.css().ensureInjected(); |
| } |
| |
| private final FlowPanel panelWidget; |
| private final FormPanel form; |
| private final FlowPanel formBody; |
| private final FormPanel redirectForm; |
| private final FlowPanel redirectBody; |
| |
| private FlowPanel errorLine; |
| private InlineLabel errorMsg; |
| |
| private Button login; |
| private NpTextBox providerId; |
| private CheckBox rememberId; |
| private boolean discovering; |
| |
| public OpenIdSignInDialog(final SignInMode requestedMode, final String token, |
| final String initialErrorMsg) { |
| super(requestedMode, token); |
| |
| formBody = new FlowPanel(); |
| formBody.setStyleName(OpenIdResources.I.css().loginForm()); |
| |
| form = new FormPanel(); |
| form.setMethod(FormPanel.METHOD_GET); |
| form.addSubmitHandler(this); |
| form.add(formBody); |
| |
| redirectBody = new FlowPanel(); |
| redirectBody.setVisible(false); |
| redirectForm = new FormPanel(); |
| redirectForm.add(redirectBody); |
| |
| panelWidget = new FlowPanel(); |
| panelWidget.add(form); |
| panelWidget.add(redirectForm); |
| add(panelWidget); |
| |
| createHeaderLogo(); |
| createHeaderText(); |
| createErrorBox(); |
| createIdentBox(); |
| |
| link(OpenIdUrls.URL_GOOGLE, OpenIdUtil.C.nameGoogle(), OpenIdResources.I |
| .iconGoogle()); |
| link(OpenIdUrls.URL_YAHOO, OpenIdUtil.C.nameYahoo(), OpenIdResources.I |
| .iconYahoo()); |
| |
| if (initialErrorMsg != null) { |
| showError(initialErrorMsg); |
| } |
| formBody.add(new HTML(OpenIdUtil.C.whatIsOpenIDHtml())); |
| } |
| |
| @Override |
| public void show() { |
| super.show(); |
| providerId.selectAll(); |
| Scheduler.get().scheduleDeferred(new ScheduledCommand() { |
| @Override |
| public void execute() { |
| providerId.setFocus(true); |
| } |
| }); |
| } |
| |
| private void createHeaderLogo() { |
| final FlowPanel headerLogo = new FlowPanel(); |
| headerLogo.setStyleName(OpenIdResources.I.css().logo()); |
| headerLogo.add(new Image(OpenIdResources.I.openidLogo())); |
| formBody.add(headerLogo); |
| } |
| |
| private void createHeaderText() { |
| final FlowPanel headerText = new FlowPanel(); |
| final String me = Window.Location.getHostName(); |
| final SmallHeading headerLabel = new SmallHeading(); |
| switch (mode) { |
| case LINK_IDENTIY: |
| headerLabel.setText(OpenIdUtil.M.linkAt(me)); |
| break; |
| case REGISTER: |
| headerLabel.setText(OpenIdUtil.M.registerAt(me)); |
| break; |
| case SIGN_IN: |
| default: |
| headerLabel.setText(OpenIdUtil.M.signInAt(me)); |
| break; |
| } |
| headerText.add(headerLabel); |
| formBody.add(headerText); |
| } |
| |
| private void createErrorBox() { |
| errorLine = new FlowPanel(); |
| DOM.setStyleAttribute(errorLine.getElement(), "visibility", "hidden"); |
| errorLine.setStyleName(OpenIdResources.I.css().error()); |
| |
| errorMsg = new InlineLabel(); |
| errorLine.add(errorMsg); |
| formBody.add(errorLine); |
| } |
| |
| private void showError(final String msgText) { |
| errorMsg.setText(msgText); |
| DOM.setStyleAttribute(errorLine.getElement(), "visibility", ""); |
| } |
| |
| private void hideError() { |
| DOM.setStyleAttribute(errorLine.getElement(), "visibility", "hidden"); |
| } |
| |
| private void createIdentBox() { |
| boolean remember = mode == SignInMode.SIGN_IN || mode == SignInMode.REGISTER; |
| |
| final FlowPanel group = new FlowPanel(); |
| group.setStyleName(OpenIdResources.I.css().loginLine()); |
| |
| final FlowPanel line1 = new FlowPanel(); |
| group.add(line1); |
| |
| providerId = new NpTextBox(); |
| providerId.setVisibleLength(60); |
| providerId.setStyleName(OpenIdResources.I.css().identifier()); |
| providerId.setTabIndex(0); |
| providerId.addKeyPressHandler(new KeyPressHandler() { |
| @Override |
| public void onKeyPress(final KeyPressEvent event) { |
| if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) { |
| event.preventDefault(); |
| form.submit(); |
| } |
| } |
| }); |
| line1.add(providerId); |
| |
| login = new Button(); |
| switch (mode) { |
| case LINK_IDENTIY: |
| login.setText(OpenIdUtil.C.buttonLinkId()); |
| break; |
| case REGISTER: |
| login.setText(OpenIdUtil.C.buttonRegister()); |
| break; |
| case SIGN_IN: |
| default: |
| login.setText(OpenIdUtil.C.buttonSignIn()); |
| break; |
| } |
| login.addClickHandler(new ClickHandler() { |
| @Override |
| public void onClick(final ClickEvent event) { |
| form.submit(); |
| } |
| }); |
| login.setTabIndex(remember ? 2 : 1); |
| line1.add(login); |
| |
| Button close = new Button(Gerrit.C.signInDialogClose()); |
| close.addClickHandler(new ClickHandler() { |
| @Override |
| public void onClick(ClickEvent event) { |
| hide(); |
| } |
| }); |
| close.setTabIndex(remember ? 3 : 2); |
| line1.add(close); |
| |
| if (remember) { |
| rememberId = new CheckBox(OpenIdUtil.C.rememberMe()); |
| rememberId.setTabIndex(1); |
| group.add(rememberId); |
| |
| String last = Cookies.getCookie(OpenIdUrls.LASTID_COOKIE); |
| if (last != null && !"".equals(last)) { |
| if (last.startsWith("\"") && last.endsWith("\"")) { |
| // Dequote the value. We shouldn't have to do this, but |
| // something is causing some Google Account tokens to get |
| // wrapped up in double quotes when obtained from the cookie. |
| // |
| last = last.substring(1, last.length() - 2); |
| } |
| providerId.setText(last); |
| rememberId.setValue(true); |
| } |
| } |
| |
| formBody.add(group); |
| } |
| |
| private void link(final String identUrl, final String who, |
| final ImageResource icon) { |
| if (!isAllowedProvider(identUrl)) { |
| return; |
| } |
| |
| final ClickHandler i = new ClickHandler() { |
| @Override |
| public void onClick(final ClickEvent event) { |
| event.preventDefault(); |
| if (!discovering) { |
| providerId.setText(identUrl); |
| form.submit(); |
| } |
| } |
| }; |
| |
| final FlowPanel line = new FlowPanel(); |
| line.addStyleName(OpenIdResources.I.css().directLink()); |
| |
| final Image img = new Image(icon); |
| img.addClickHandler(i); |
| line.add(img); |
| |
| final Anchor text = new Anchor(); |
| switch (mode) { |
| case LINK_IDENTIY: |
| text.setText(OpenIdUtil.M.linkWith(who)); |
| break; |
| case REGISTER: |
| text.setText(OpenIdUtil.M.registerWith(who)); |
| break; |
| case SIGN_IN: |
| default: |
| text.setText(OpenIdUtil.M.signInWith(who)); |
| break; |
| } |
| text.setHref(identUrl); |
| text.addClickHandler(i); |
| line.add(text); |
| |
| formBody.add(line); |
| } |
| |
| private static boolean isAllowedProvider(final String identUrl) { |
| for (OpenIdProviderPattern p : Gerrit.getConfig().getAllowedOpenIDs()) { |
| if (p.matches(identUrl)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private void enable(final boolean on) { |
| providerId.setEnabled(on); |
| login.setEnabled(on); |
| } |
| |
| private void onDiscovery(final DiscoveryResult result) { |
| discovering = false; |
| |
| switch (result.status) { |
| case VALID: |
| // The provider won't support operation inside an IFRAME, |
| // so we replace our entire application. |
| // |
| redirectForm.setMethod(FormPanel.METHOD_POST); |
| redirectForm.setAction(result.providerUrl); |
| redirectBody.clear(); |
| for (final Map.Entry<String, String> e : result.providerArgs.entrySet()) { |
| redirectBody.add(new Hidden(e.getKey(), e.getValue())); |
| } |
| FormElement.as(redirectForm.getElement()).setTarget("_top"); |
| redirectForm.submit(); |
| break; |
| |
| case NOT_ALLOWED: |
| showError(OpenIdUtil.C.notAllowed()); |
| enableRetryDiscovery(); |
| break; |
| |
| case NO_PROVIDER: |
| showError(OpenIdUtil.C.noProvider()); |
| enableRetryDiscovery(); |
| break; |
| |
| case ERROR: |
| default: |
| showError(OpenIdUtil.C.error()); |
| enableRetryDiscovery(); |
| break; |
| } |
| } |
| |
| private void enableRetryDiscovery() { |
| enable(true); |
| providerId.selectAll(); |
| providerId.setFocus(true); |
| } |
| |
| @Override |
| public void onSubmit(final SubmitEvent event) { |
| event.cancel(); |
| |
| String openidIdentifier = providerId.getText(); |
| if (openidIdentifier == null || openidIdentifier.equals("")) { |
| enable(true); |
| return; |
| } |
| |
| if (!openidIdentifier.startsWith("http://") |
| && !openidIdentifier.startsWith("https://")) { |
| openidIdentifier = "http://" + openidIdentifier; |
| } |
| |
| if (!isAllowedProvider(openidIdentifier)) { |
| showError(OpenIdUtil.C.notAllowed()); |
| enableRetryDiscovery(); |
| return; |
| } |
| |
| discovering = true; |
| enable(false); |
| hideError(); |
| |
| final boolean remember = rememberId != null && rememberId.getValue(); |
| OpenIdUtil.SVC.discover(openidIdentifier, mode, remember, token, |
| new GerritCallback<DiscoveryResult>() { |
| public void onSuccess(final DiscoveryResult result) { |
| onDiscovery(result); |
| } |
| |
| @Override |
| public void onFailure(final Throwable caught) { |
| super.onFailure(caught); |
| enableRetryDiscovery(); |
| } |
| }); |
| } |
| |
| public void onSubmitComplete(final FormSubmitCompleteEvent event) { |
| } |
| } |