package com.bloatit.web.linkable.oauth2;
import java.util.Map.Entry;
import org.apache.amber.oauth2.common.OAuth;
import org.apache.commons.codec.EncoderException;
import org.apache.commons.codec.net.URLCodec;
import com.bloatit.framework.exceptions.highlevel.ExternalErrorException;
import com.bloatit.framework.exceptions.lowlevel.RedirectException;
import com.bloatit.framework.oauthprocessor.OAuthProcessor;
import com.bloatit.framework.utils.parameters.HttpParameter;
import com.bloatit.framework.webprocessor.annotations.NonOptional;
import com.bloatit.framework.webprocessor.annotations.Optional;
import com.bloatit.framework.webprocessor.annotations.ParamContainer;
import com.bloatit.framework.webprocessor.annotations.RequestParam;
import com.bloatit.framework.webprocessor.annotations.tr;
import com.bloatit.framework.webprocessor.components.HtmlDiv;
import com.bloatit.framework.webprocessor.components.HtmlLink;
import com.bloatit.framework.webprocessor.components.HtmlTitleBlock;
import com.bloatit.framework.webprocessor.components.form.HtmlForm;
import com.bloatit.framework.webprocessor.components.form.HtmlPasswordField;
import com.bloatit.framework.webprocessor.components.form.HtmlSubmit;
import com.bloatit.framework.webprocessor.components.form.HtmlTextField;
import com.bloatit.framework.webprocessor.components.meta.HtmlElement;
import com.bloatit.framework.webprocessor.context.Context;
import com.bloatit.model.ExternalService;
import com.bloatit.model.managers.ExternalServiceManager;
import com.bloatit.web.linkable.IndexPage;
import com.bloatit.web.linkable.master.Breadcrumb;
import com.bloatit.web.linkable.master.ElveosPage;
import com.bloatit.web.url.IndexPageUrl;
import com.bloatit.web.url.OAuthAuthorizationPageUrl;
@ParamContainer(OAuthProcessor.OAUTH_GET_CREDENTIAL_PAGENAME)
public class OAuthAuthorizationPage extends ElveosPage {
private final OAuthAuthorizationPageUrl url;
/**
* REQUIRED. Value MUST be set to "code".
*/
@RequestParam(name = OAuth.OAUTH_RESPONSE_TYPE)
@NonOptional(@tr("OAuth request need a %paramName% parameter."))
private final String responseType;
/**
* REQUIRED. The client identifier as described in Section 2.3.
*/
@RequestParam(name = OAuth.OAUTH_CLIENT_ID)
@NonOptional(@tr("OAuth request need a %paramName% parameter."))
private final String clientId;
/**
* OPTIONAL, as described in Section 3.1.2.
*/
// FIXME: I am non optional because I don't know what to do if there is no
// redirectUri
@RequestParam(name = OAuth.OAUTH_REDIRECT_URI)
@NonOptional(@tr("OAuth request need a %paramName% parameter."))
private final String redirectUri;
/**
* OPTIONAL. The scope of the access request expressed as a list of
* space-delimited, case sensitive strings. The value is defined by the
* authorization server. If the value contains multiple space-delimited
* strings, their order does not matter, and each string adds an additional
* access range to the requested scope.
*/
@Optional
@RequestParam(name = OAuth.OAUTH_SCOPE)
@SuppressWarnings("unused")
private final String scope;
/**
* OPTIONAL. An opaque value used by the client to maintain state between
* the request and callback. The authorization server includes this value
* when redirecting the user-agent back to the client.
*/
@RequestParam(name = OAuth.OAUTH_STATE)
@Optional
@SuppressWarnings("unused")
private final String state;
@RequestParam(name = "fail")
@Optional
private final Boolean fail;
public OAuthAuthorizationPage(final OAuthAuthorizationPageUrl url) {
super(url);
this.url = url;
this.clientId = url.getClientId();
this.redirectUri = url.getRedirectUri();
this.responseType = url.getResponseType();
this.scope = url.getScope();
this.state = url.getState();
this.fail = url.getFail();
}
@Override
public HtmlElement createBodyContent() throws RedirectException {
if (fail != null && fail) {
getSession().notifyError(Context.tr("Wrong login or password, please retry."));
}
final ExternalService service = ExternalServiceManager.getByToken(clientId);
if (service == null) {
getSession().notifyError(Context.tr("Service not found!"));
throw new RedirectException(new IndexPageUrl());
}
final String yesUrl = createYesUrl();
// TODO make this page pretty(er) !
final HtmlDiv div = new HtmlDiv("oauth_question");
{
final HtmlTitleBlock loginTitle = new HtmlTitleBlock(Context.tr("Enter your login and password to grant ''{0}'' the right to access your Elveos account ?",
service.getDescription().getDefaultTranslation().getTitle()),
1);
div.add(loginTitle);
final HtmlForm loginForm = new HtmlForm(yesUrl);
div.add(loginForm);
// Login field
final HtmlTextField loginInput = new HtmlTextField(OAuthProcessor.LOGIN_CODE, Context.trc("Login (noun)", "Login"));
loginForm.add(loginInput);
// passwordField
final HtmlPasswordField passwordInput = new HtmlPasswordField(OAuthProcessor.PASSWORD_CODE, Context.tr("Password"));
loginForm.add(passwordInput);
// Submit
final HtmlDiv yesOrNoDiv = new HtmlDiv("login_or_signup");
loginForm.add(yesOrNoDiv);
final HtmlSubmit submitButton = new HtmlSubmit(Context.tr("Yes, I trust {0}", service.getDescription().getDefaultTranslation().getTitle()));
// submitButton.setCssClass("button_good");
yesOrNoDiv.add(new HtmlLink("/oauth/" + OAuthProcessor.DENY_AUTHORIZATION_PAGE_NAME, Context.tr("No")).setCssClass("button_bad"));
yesOrNoDiv.add(submitButton);
}
return div;
}
private String createYesUrl() {
final StringBuilder sb = new StringBuilder();
sb.append("/oauth/");
sb.append(OAuthProcessor.GET_AUTHORIZATION_PAGE_NAME);
sb.append("?");
final URLCodec urlCodec = new URLCodec();
for (final Entry<String, HttpParameter> param : url.getStringParameters().entrySet()) {
for (final String value : param.getValue()) {
sb.append(param.getKey());
sb.append("=");
try {
sb.append(urlCodec.encode(value));
} catch (final EncoderException e) {
throw new ExternalErrorException(e);
}
sb.append("&");
}
}
return sb.toString();
}
@Override
protected Breadcrumb createBreadcrumb() {
return generateBreadcrumb(responseType, clientId, redirectUri);
}
public static Breadcrumb generateBreadcrumb(final String responseType, final String clientId, final String redirectUri) {
final Breadcrumb breadcrumb = IndexPage.generateBreadcrumb();
breadcrumb.pushLink(new OAuthAuthorizationPageUrl(responseType, clientId, redirectUri).getHtmlLink(Context.tr("oauth authorization")));
return breadcrumb;
}
@Override
protected String createPageTitle() {
return Context.tr("Authorize other application to access your elveos account");
}
@Override
public boolean isStable() {
return false;
}
}