blob: cd2c493d224621b64c9cdebdc77186e963ee9cad [file] [log] [blame]
// 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) {
}
}