2 * Copyright (c) 2010-2022 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.core.thing.ThingUID;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
32 * Servlet gathers and processes required information to perform an authorization with the Miele cloud service
33 * and create a bridge afterwards. Required parameters are the client ID, client secret, an ID for the bridge and an
34 * e-mail address. If the given parameters are valid, the browser is redirected to the Miele service login. Otherwise,
35 * the browser is redirected to the previous page with an according error message.
37 * @author Björn Lange - Initial Contribution
40 public final class ForwardToLoginServlet extends AbstractRedirectionServlet {
41 private static final long serialVersionUID = -9094642228439994183L;
43 public static final String CLIENT_ID_PARAMETER_NAME = "clientId";
44 public static final String CLIENT_SECRET_PARAMETER_NAME = "clientSecret";
45 public static final String BRIDGE_ID_PARAMETER_NAME = "bridgeId";
46 public static final String EMAIL_PARAMETER_NAME = "email";
48 private final Logger logger = LoggerFactory.getLogger(ForwardToLoginServlet.class);
50 private final OAuthAuthorizationHandler authorizationHandler;
53 * Creates a new {@link ForwardToLoginServlet}.
55 * @param authorizationHandler Handler implementing the OAuth authorization process.
57 public ForwardToLoginServlet(OAuthAuthorizationHandler authorizationHandler) {
58 this.authorizationHandler = authorizationHandler;
62 protected String getRedirectionDestination(HttpServletRequest request) {
63 String clientId = request.getParameter(CLIENT_ID_PARAMETER_NAME);
64 String clientSecret = request.getParameter(CLIENT_SECRET_PARAMETER_NAME);
65 String bridgeId = request.getParameter(BRIDGE_ID_PARAMETER_NAME);
66 String email = request.getParameter(EMAIL_PARAMETER_NAME);
68 if (clientId == null || clientId.isEmpty()) {
69 logger.warn("Request is missing client ID.");
70 return getErrorRedirectionUrl(PairAccountServlet.MISSING_CLIENT_ID_PARAMETER_NAME);
72 clientId = clientId.strip();
74 if (clientSecret == null || clientSecret.isEmpty()) {
75 logger.warn("Request is missing client secret.");
76 return getErrorRedirectionUrl(PairAccountServlet.MISSING_CLIENT_SECRET_PARAMETER_NAME);
78 clientSecret = clientSecret.strip();
80 if (bridgeId == null || bridgeId.isEmpty()) {
81 logger.warn("Request is missing bridge ID.");
82 return getErrorRedirectionUrl(PairAccountServlet.MISSING_BRIDGE_ID_PARAMETER_NAME);
84 bridgeId = bridgeId.strip();
86 if (email == null || email.isEmpty()) {
87 logger.warn("Request is missing e-mail address.");
88 return getErrorRedirectionUrl(PairAccountServlet.MISSING_EMAIL_PARAMETER_NAME);
90 email = email.strip();
92 ThingUID bridgeUid = null;
94 bridgeUid = new ThingUID(MieleCloudBindingConstants.THING_TYPE_BRIDGE, bridgeId);
95 } catch (IllegalArgumentException e) {
96 logger.warn("Passed bridge ID '{}' is invalid.", bridgeId);
97 return getErrorRedirectionUrl(PairAccountServlet.MALFORMED_BRIDGE_ID_PARAMETER_NAME);
101 authorizationHandler.beginAuthorization(clientId, clientSecret, bridgeUid, email);
102 } catch (OngoingAuthorizationException e) {
103 logger.warn("Cannot begin new authorization process while another one is still running.");
104 return getErrorRedirectUrlWithExpiryTime(e.getOngoingAuthorizationExpiryTimestamp());
107 StringBuffer requestUrl = request.getRequestURL();
108 if (requestUrl == null) {
109 return getErrorRedirectionUrl(PairAccountServlet.MISSING_REQUEST_URL_PARAMETER_NAME);
113 return authorizationHandler.getAuthorizationUrl(deriveRedirectUri(requestUrl.toString()));
114 } catch (NoOngoingAuthorizationException e) {
116 "Failed to create authorization URL: There was no ongoing authorization although we just started one.");
117 return getErrorRedirectionUrl(PairAccountServlet.NO_ONGOING_AUTHORIZATION_IN_STEP2_PARAMETER_NAME);
118 } catch (OAuthException e) {
119 logger.warn("Failed to create authorization URL.", e);
120 return getErrorRedirectionUrl(PairAccountServlet.FAILED_TO_DERIVE_REDIRECT_URL_PARAMETER_NAME);
124 private String getErrorRedirectUrlWithExpiryTime(@Nullable LocalDateTime ongoingAuthorizationExpiryTimestamp) {
125 if (ongoingAuthorizationExpiryTimestamp == null) {
126 return getErrorRedirectionUrl(
127 PairAccountServlet.ONGOING_AUTHORIZATION_IN_STEP1_EXPIRES_IN_MINUTES_PARAMETER_NAME,
128 PairAccountServlet.ONGOING_AUTHORIZATION_UNKNOWN_EXPIRY_TIME);
131 long minutesUntilExpiry = ChronoUnit.MINUTES.between(LocalDateTime.now(), ongoingAuthorizationExpiryTimestamp)
133 return getErrorRedirectionUrl(
134 PairAccountServlet.ONGOING_AUTHORIZATION_IN_STEP1_EXPIRES_IN_MINUTES_PARAMETER_NAME,
135 Long.toString(minutesUntilExpiry));
138 private String getErrorRedirectionUrl(String errorCode) {
139 return getErrorRedirectionUrl(errorCode, "true");
142 private String getErrorRedirectionUrl(String errorCode, String parameterValue) {
143 return "/mielecloud/pair?" + errorCode + "=" + parameterValue;
146 private String deriveRedirectUri(String requestUrl) {
147 return requestUrl + "/../result";