/* * Atricore IDBus * * Copyright (c) 2009, Atricore Inc. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.atricore.idbus.capabilities.openid.ui.panel; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; import org.apache.wicket.ajax.form.AjaxFormValidatingBehavior; import org.apache.wicket.ajax.markup.html.form.AjaxButton; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.RequiredTextField; import org.apache.wicket.markup.html.form.StatelessForm; import org.apache.wicket.markup.html.panel.FeedbackPanel; import org.apache.wicket.model.PropertyModel; import org.apache.wicket.request.http.handler.RedirectRequestHandler; import org.apache.wicket.util.time.Duration; import org.apache.wicket.util.value.ValueMap; import org.apache.wicket.validation.validator.UrlValidator; import org.atricore.idbus.capabilities.sso.main.claims.SSOCredentialClaimsRequest; import org.atricore.idbus.capabilities.sso.support.auth.AuthnCtxClass; import org.atricore.idbus.capabilities.sso.support.binding.SSOBinding; import org.atricore.idbus.capabilities.sso.ui.components.GtFeedbackPanel; import org.atricore.idbus.capabilities.sso.ui.page.authn.BaseSignInPanel; import org.atricore.idbus.kernel.main.federation.metadata.EndpointDescriptor; import org.atricore.idbus.kernel.main.mediation.*; import org.atricore.idbus.kernel.main.mediation.camel.component.binding.AbstractMediationHttpBinding; import org.atricore.idbus.kernel.main.mediation.claim.*; import org.atricore.idbus.kernel.main.util.UUIDGenerator; /** * Sign-in panel for OpenID authentication for collecting user's OpenID. * * @author <a href="mailto:gbrigandi@atricore.org">Gianluca Brigandi</a> */ public class OpenIDSignInPanel extends BaseSignInPanel { private static final Log logger = LogFactory.getLog(OpenIDSignInPanel.class); private static final long serialVersionUID = 1L; /** * Field for user name. */ private RequiredTextField<String> openid; private AjaxButton submit; /** * Error information */ protected FeedbackPanel feedbackPanel; /** * Error information */ protected WebMarkupContainer feedbackBox; /** * Sign in form. */ public final class OpenIDSignInForm extends StatelessForm<Void> { private static final long serialVersionUID = 1L; /** * El-cheapo model for form. */ private final ValueMap properties = new ValueMap(); /** * Constructor. * * @param id id of the form component */ public OpenIDSignInForm(final String id) { super(id); // Attach textfield components that edit properties map // in lieu of a formal beans model add(openid = new RequiredTextField<String>("openid", new PropertyModel<String>(properties, "openid"))); openid.setType(String.class); openid.add(new UrlValidator()); openid.add(new AjaxFormComponentUpdatingBehavior("onchange") { @Override protected void onUpdate(AjaxRequestTarget target) { submit.setEnabled(true); target.add(submit); } }); openid.setOutputMarkupId(true); } } /** * @param id See Component constructor * @see org.apache.wicket.Component#Component(String) */ public OpenIDSignInPanel(final String id, SSOCredentialClaimsRequest credentialClaimsRequest, MessageQueueManager artifactQueueManager, final IdentityMediationUnitRegistry idsuRegistry) { super(id); this.credentialClaimsRequest = credentialClaimsRequest; this.artifactQueueManager = artifactQueueManager; this.idsuRegistry = idsuRegistry; } @Override protected void onInitialize() { super.onInitialize(); // Create feedback panel and add to page super.onInitialize(); // 1. Feedback Panel feedbackBox = buildFeedbackBox(); feedbackPanel = (FeedbackPanel) feedbackBox.get("feedback"); // Add sign-in form to page, passing feedback panel as // validation error handler OpenIDSignInForm form = new OpenIDSignInForm("signInForm"); AjaxFormValidatingBehavior.addToAllFormComponents(form, "onkeyup", Duration.ONE_SECOND); form.setOutputMarkupId(true); // add a button that can be used to submit the form via ajax submit = new AjaxButton("apply", form) { @Override protected void onSubmit(AjaxRequestTarget target, Form<?> form) { // repaint the feedback panel so that it is hidden target.add(feedbackPanel); try { String claimsConsumerUrl = signIn(getOpenid()); onSignInSucceeded(claimsConsumerUrl); } catch (Exception e) { logger.error("Fatal error during signIn : " + e.getMessage(), e); onSignInFailed(); } } @Override protected void onError(AjaxRequestTarget target, Form<?> form) { // repaint the feedback panel so errors are shown target.add(feedbackPanel); } }; submit.setEnabled(false); form.add(submit); add(form); // If the form does not provide a feedbackBox, we should do it ! if (form.get("feedbackBox") == null) add(feedbackBox); } /** * Removes persisted form data for the signin panel (forget me) */ public final void forgetMe() { // Remove persisted user data. Search for child component // of type OpenIDSignInForm and remove its related persistence values. // getPage().removePersistedFormData(OpenIDSignInForm.class, true); } /** * Convenience method to access the openid. * * @return The user name */ public String getOpenid() { return openid.getDefaultModelObjectAsString(); } /** * Convenience method set persistence for openid and password. * * @param enable Whether the fields should be persistent */ public void setPersistent(final boolean enable) { // openid.setPersistent(enable); } /** * Sign in user if possible. * * @param openid The openid * @return True if signin was successful */ public String signIn(String openid) throws Exception { UUIDGenerator idGenerator = new UUIDGenerator(); if (logger.isDebugEnabled()) logger.debug("Claims Request = " + credentialClaimsRequest); ClaimSet claims = new ClaimSetImpl(); claims.addClaim(new CredentialClaimImpl("openid", openid)); //claims.addClaim(new ClaimImpl("rememberMe", cmd.isRememberMe())); CredentialClaimsResponse responseCredential = new CredentialClaimsResponseImpl(idGenerator.generateId(), null, credentialClaimsRequest.getId(), claims, credentialClaimsRequest.getRelayState()); EndpointDescriptor claimsEndpoint = resolveClaimsEndpoint(credentialClaimsRequest, AuthnCtxClass.OPENID_AUTHN_CTX); if (claimsEndpoint == null) { logger.error("No claims endpoint found!"); // TODO : Create error and redirect to error view using 'IDBusErrArt' } if (!claimsEndpoint.getBinding().equals(SSOBinding.SSO_ARTIFACT.getValue())) { logger.error("Invalid endpoint binding for claims response : " + claimsEndpoint.getBinding()); // TODO : Create error and redirect to error view using 'IDBusErrArt' } String claimsEndpointUrl = claimsEndpoint.getResponseLocation() != null ? claimsEndpoint.getResponseLocation() : claimsEndpoint.getLocation(); if (logger.isDebugEnabled()) logger.debug("Using claims endpoint URL [" + claimsEndpointUrl + "]"); Artifact a = artifactQueueManager.pushMessage(responseCredential); claimsEndpointUrl += "?SSOArt=" + a.getContent(); if (logger.isDebugEnabled()) logger.debug("Returning claims to " + claimsEndpointUrl); return claimsEndpointUrl; } protected void onSignInFailed() { // Try the component based localizer first. If not found try the // application localizer. Else use the default error(getLocalizer().getString("signInFailed", this, "Sign in failed")); } protected void onSignInSucceeded(String claimsConsumerUrl) { getRequestCycle().scheduleRequestHandlerAfterCurrent(new RedirectRequestHandler(claimsConsumerUrl)); } /** * Build the container for error messages */ protected WebMarkupContainer buildFeedbackBox() { // Create feedback panel and add it to page feedbackBox = new WebMarkupContainer("feedbackBox"); feedbackPanel = new GtFeedbackPanel("feedback"); feedbackPanel.setOutputMarkupId(true); feedbackBox.add(feedbackPanel); return feedbackBox; } }