blob: 44c4e233d8139e0fef64da3400f5dcf5fd11a4e8 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.syncope.client.ui.commons;
import com.googlecode.wicket.kendo.ui.widget.notification.Notification;
import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import org.apache.syncope.client.ui.commons.panels.NotificationPanel;
import org.apache.syncope.common.keymaster.client.api.DomainOps;
import org.apache.syncope.common.keymaster.client.api.model.Domain;
import javax.ws.rs.core.HttpHeaders;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.OnLoadHeaderItem;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.ChoiceRenderer;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.PasswordTextField;
import org.apache.wicket.markup.html.form.StatelessForm;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class BaseLogin extends WebPage {
private static final long serialVersionUID = 5889157642852559004L;
protected static final Logger LOG = LoggerFactory.getLogger(BaseLogin.class);
public static final List<Locale> SUPPORTED_LOCALES = List.of(
Locale.ENGLISH, Locale.CANADA_FRENCH, Locale.ITALIAN, Locale.JAPANESE, new Locale("pt", "BR"),
new Locale("ru"));
@SpringBean
private DomainOps domainOps;
protected final NotificationPanel notificationPanel;
protected final StatelessForm<Void> form;
private final TextField<String> usernameField;
private final TextField<String> passwordField;
protected String notificationMessage;
protected String notificationLevel;
private final LoadableDetachableModel<List<String>> domains = new LoadableDetachableModel<List<String>>() {
private static final long serialVersionUID = 4659376149825914247L;
@Override
protected List<String> load() {
List<String> current = new ArrayList<>();
current.addAll(domainOps.list().stream().map(Domain::getKey).sorted().collect(Collectors.toList()));
current.add(0, SyncopeConstants.MASTER_DOMAIN);
return current;
}
};
public BaseLogin(final PageParameters parameters) {
super(parameters);
setStatelessHint(true);
notificationPanel = new NotificationPanel(Constants.FEEDBACK);
add(notificationPanel);
if (!parameters.get("notificationMessage").isNull()) {
notificationMessage = parameters.get(Constants.NOTIFICATION_MSG_PARAM).toString();
notificationLevel = parameters.get(Constants.NOTIFICATION_LEVEL_PARAM).isEmpty()
? Notification.SUCCESS
: parameters.get(Constants.NOTIFICATION_LEVEL_PARAM).toString();
}
Label exceptionMessage = new Label("exceptionMessage");
exceptionMessage.setOutputMarkupPlaceholderTag(true);
exceptionMessage.setVisible(false);
if (!parameters.get("errorMessage").isNull()) {
exceptionMessage.setVisible(true);
exceptionMessage.setDefaultModel(Model.of(parameters.get("errorMessage")));
}
add(exceptionMessage);
form = new StatelessForm<>("login");
usernameField = new TextField<>("username", new Model<>());
usernameField.setMarkupId("username");
form.add(usernameField);
passwordField = new PasswordTextField("password", new Model<>());
passwordField.setMarkupId("password");
form.add(passwordField);
LocaleDropDown languageSelect = new LocaleDropDown("language");
languageSelect.add(new AjaxFormComponentUpdatingBehavior(Constants.ON_BLUR) {
private static final long serialVersionUID = -1107858522700306810L;
@Override
protected void onUpdate(final AjaxRequestTarget target) {
getLanguageOnChangeComponents().forEach(target::add);
}
}).add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
private static final long serialVersionUID = -1107858522700306810L;
@Override
protected void onUpdate(final AjaxRequestTarget target) {
getLanguageOnChangeComponents().forEach(target::add);
}
});
form.add(languageSelect.setOutputMarkupId(true));
DomainDropDown domainSelect = new DomainDropDown("domain", domains);
domainSelect.add(new AjaxFormComponentUpdatingBehavior(Constants.ON_BLUR) {
private static final long serialVersionUID = -1107858522700306810L;
@Override
protected void onUpdate(final AjaxRequestTarget target) {
getDomainOnChangeComponents().forEach(target::add);
}
}).add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
private static final long serialVersionUID = -1107858522700306810L;
@Override
protected void onUpdate(final AjaxRequestTarget target) {
getDomainOnChangeComponents().forEach(target::add);
}
});
form.add(domainSelect.setOutputMarkupId(true));
AjaxButton submitButton = new AjaxButton("submit", new Model<>(getString("submit"))) {
private static final long serialVersionUID = 429178684321093953L;
@Override
protected void onSubmit(final AjaxRequestTarget target) {
authenticate(usernameField.getRawInput(), passwordField.getRawInput(), target);
}
};
submitButton.setDefaultFormProcessing(false);
form.add(submitButton);
form.setDefaultButton(submitButton);
List<Panel> ssoLoginFormPanels = getSSOLoginFormPanels();
ListView<Panel> ssoLogins = new ListView<Panel>("ssoLogins", ssoLoginFormPanels) {
private static final long serialVersionUID = -9180479401817023838L;
@Override
protected void populateItem(final ListItem<Panel> item) {
item.add(item.getModelObject());
}
};
form.add(ssoLogins);
add(form);
}
protected Collection<Component> getLanguageOnChangeComponents() {
return List.of(form);
}
protected Collection<Component> getDomainOnChangeComponents() {
return List.of(form);
}
@Override
public void renderHead(final IHeaderResponse response) {
super.renderHead(response);
if (StringUtils.isNotBlank(notificationMessage)) {
response.render(OnLoadHeaderItem.forScript(StyledNotificationBehavior.jQueryShow(notificationMessage,
String.format("jQuery('#%s').data('kendoNotification')",
notificationPanel.getNotificationMarkupId()), notificationLevel)));
}
}
protected abstract BaseSession getBaseSession();
protected abstract List<Panel> getSSOLoginFormPanels();
protected abstract void sendError(String error);
protected abstract String getAnonymousUser();
protected abstract void authenticate(
String username,
String password,
AjaxRequestTarget target)
throws AccessControlException;
/**
* Inner class which implements (custom) Locale DropDownChoice component.
*/
private class LocaleDropDown extends DropDownChoice<Locale> {
private static final long serialVersionUID = 2349382679992357202L;
private class LocaleRenderer extends ChoiceRenderer<Locale> {
private static final long serialVersionUID = -3657529581555164741L;
@Override
public String getDisplayValue(final Locale locale) {
return locale.getDisplayName(getLocale());
}
}
LocaleDropDown(final String id) {
super(id, SUPPORTED_LOCALES);
setChoiceRenderer(new LocaleRenderer());
setModel(new IModel<Locale>() {
private static final long serialVersionUID = -6985170095629312963L;
@Override
public Locale getObject() {
return getSession().getLocale();
}
@Override
public void setObject(final Locale object) {
getSession().setLocale(object);
}
@Override
public void detach() {
// Empty.
}
});
// set default language selection
List<Locale> filtered = List.of();
String acceptLanguage = ((ServletWebRequest) RequestCycle.get().getRequest()).
getHeader(HttpHeaders.ACCEPT_LANGUAGE);
if (StringUtils.isNotBlank(acceptLanguage)) {
try {
filtered = Locale.filter(Locale.LanguageRange.parse(acceptLanguage), SUPPORTED_LOCALES);
} catch (Exception e) {
LOG.debug("Could not parse {} HTTP header value '{}'",
HttpHeaders.ACCEPT_LANGUAGE, acceptLanguage, e);
}
}
getModel().setObject(filtered.isEmpty()
? Locale.ENGLISH
: filtered.get(0));
}
}
}