2 * Copyright (c) 2010-2021 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.mielecloud.internal.config.servlet;
15 import java.time.LocalDateTime;
16 import java.time.temporal.ChronoUnit;
18 import javax.servlet.http.HttpServletRequest;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.binding.mielecloud.internal.MieleCloudBindingConstants;
23 import org.openhab.binding.mielecloud.internal.auth.OAuthException;
24 import org.openhab.binding.mielecloud.internal.config.OAuthAuthorizationHandler;
25 import org.openhab.binding.mielecloud.internal.config.exception.NoOngoingAuthorizationException;
26 import org.openhab.binding.mielecloud.internal.config.exception.OngoingAuthorizationException;
27 import org.openhab.binding.mielecloud.internal.util.EmailValidator;
28 import org.openhab.core.thing.ThingUID;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
33 * Servlet gathers and processes required information to perform an authorization with the Miele cloud service
34 * and create a bridge afterwards. Required parameters are the client ID, client secret, an ID for the bridge and an
35 * e-mail address. If the given parameters are valid, the browser is redirected to the Miele service login. Otherwise,
36 * the browser is redirected to the previous page with an according error message.
38 * @author Björn Lange - Initial Contribution
41 public final class ForwardToLoginServlet extends AbstractRedirectionServlet {
42 private static final long serialVersionUID = -9094642228439994183L;
44 public static final String CLIENT_ID_PARAMETER_NAME = "clientId";
45 public static final String CLIENT_SECRET_PARAMETER_NAME = "clientSecret";
46 public static final String BRIDGE_ID_PARAMETER_NAME = "bridgeId";
47 public static final String EMAIL_PARAMETER_NAME = "email";
49 private final Logger logger = LoggerFactory.getLogger(ForwardToLoginServlet.class);
51 private final OAuthAuthorizationHandler authorizationHandler;
54 * Creates a new {@link ForwardToLoginServlet}.
56 * @param authorizationHandler Handler implementing the OAuth authorization process.
58 public ForwardToLoginServlet(OAuthAuthorizationHandler authorizationHandler) {
59 this.authorizationHandler = authorizationHandler;
63 protected String getRedirectionDestination(HttpServletRequest request) {
64 String clientId = request.getParameter(CLIENT_ID_PARAMETER_NAME);
65 String clientSecret = request.getParameter(CLIENT_SECRET_PARAMETER_NAME);
66 String bridgeId = request.getParameter(BRIDGE_ID_PARAMETER_NAME);
67 String email = request.getParameter(EMAIL_PARAMETER_NAME);
69 if (clientId == null || clientId.isEmpty()) {
70 logger.warn("Request is missing client ID.");
71 return getErrorRedirectionUrl(PairAccountServlet.MISSING_CLIENT_ID_PARAMETER_NAME);
73 if (clientSecret == null || clientSecret.isEmpty()) {
74 logger.warn("Request is missing client secret.");
75 return getErrorRedirectionUrl(PairAccountServlet.MISSING_CLIENT_SECRET_PARAMETER_NAME);
77 if (bridgeId == null || bridgeId.isEmpty()) {
78 logger.warn("Request is missing bridge ID.");
79 return getErrorRedirectionUrl(PairAccountServlet.MISSING_BRIDGE_ID_PARAMETER_NAME);
81 if (email == null || email.isEmpty()) {
82 logger.warn("Request is missing e-mail address.");
83 return getErrorRedirectionUrl(PairAccountServlet.MISSING_EMAIL_PARAMETER_NAME);
86 ThingUID bridgeUid = null;
88 bridgeUid = new ThingUID(MieleCloudBindingConstants.THING_TYPE_BRIDGE, bridgeId);
89 } catch (IllegalArgumentException e) {
90 logger.warn("Passed bridge ID '{}' is invalid.", bridgeId);
91 return getErrorRedirectionUrl(PairAccountServlet.MALFORMED_BRIDGE_ID_PARAMETER_NAME);
94 if (!EmailValidator.isValid(email)) {
95 logger.warn("Passed e-mail address '{}' is invalid.", email);
96 return getErrorRedirectionUrl(PairAccountServlet.MALFORMED_EMAIL_PARAMETER_NAME);
100 authorizationHandler.beginAuthorization(clientId, clientSecret, bridgeUid, email);
101 } catch (OngoingAuthorizationException e) {
102 logger.warn("Cannot begin new authorization process while another one is still running.");
103 return getErrorRedirectUrlWithExpiryTime(e.getOngoingAuthorizationExpiryTimestamp());
106 StringBuffer requestUrl = request.getRequestURL();
107 if (requestUrl == null) {
108 return getErrorRedirectionUrl(PairAccountServlet.MISSING_REQUEST_URL_PARAMETER_NAME);
112 return authorizationHandler.getAuthorizationUrl(deriveRedirectUri(requestUrl.toString()));
113 } catch (NoOngoingAuthorizationException e) {
115 "Failed to create authorization URL: There was no ongoing authorization although we just started one.");
116 return getErrorRedirectionUrl(PairAccountServlet.NO_ONGOING_AUTHORIZATION_IN_STEP2_PARAMETER_NAME);
117 } catch (OAuthException e) {
118 logger.warn("Failed to create authorization URL.", e);
119 return getErrorRedirectionUrl(PairAccountServlet.FAILED_TO_DERIVE_REDIRECT_URL_PARAMETER_NAME);
123 private String getErrorRedirectUrlWithExpiryTime(@Nullable LocalDateTime ongoingAuthorizationExpiryTimestamp) {
124 if (ongoingAuthorizationExpiryTimestamp == null) {
125 return getErrorRedirectionUrl(
126 PairAccountServlet.ONGOING_AUTHORIZATION_IN_STEP1_EXPIRES_IN_MINUTES_PARAMETER_NAME,
127 PairAccountServlet.ONGOING_AUTHORIZATION_UNKNOWN_EXPIRY_TIME);
130 long minutesUntilExpiry = ChronoUnit.MINUTES.between(LocalDateTime.now(), ongoingAuthorizationExpiryTimestamp)
132 return getErrorRedirectionUrl(
133 PairAccountServlet.ONGOING_AUTHORIZATION_IN_STEP1_EXPIRES_IN_MINUTES_PARAMETER_NAME,
134 Long.toString(minutesUntilExpiry));
137 private String getErrorRedirectionUrl(String errorCode) {
138 return getErrorRedirectionUrl(errorCode, "true");
141 private String getErrorRedirectionUrl(String errorCode, String parameterValue) {
142 return "/mielecloud/pair?" + errorCode + "=" + parameterValue;
145 private String deriveRedirectUri(String requestUrl) {
146 return requestUrl + "/../result";