]> git.basschouten.com Git - openhab-addons.git/blob
bfa61b9676663cbaf68ceb47f087fc2aa163b3ed
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.mielecloud.internal.config.servlet;
14
15 import java.time.LocalDateTime;
16 import java.time.temporal.ChronoUnit;
17
18 import javax.servlet.http.HttpServletRequest;
19
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;
30
31 /**
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.
36  *
37  * @author Björn Lange - Initial Contribution
38  */
39 @NonNullByDefault
40 public final class ForwardToLoginServlet extends AbstractRedirectionServlet {
41     private static final long serialVersionUID = -9094642228439994183L;
42
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";
47
48     private final Logger logger = LoggerFactory.getLogger(ForwardToLoginServlet.class);
49
50     private final OAuthAuthorizationHandler authorizationHandler;
51
52     /**
53      * Creates a new {@link ForwardToLoginServlet}.
54      *
55      * @param authorizationHandler Handler implementing the OAuth authorization process.
56      */
57     public ForwardToLoginServlet(OAuthAuthorizationHandler authorizationHandler) {
58         this.authorizationHandler = authorizationHandler;
59     }
60
61     @Override
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);
67
68         if (clientId == null || clientId.isEmpty()) {
69             logger.warn("Request is missing client ID.");
70             return getErrorRedirectionUrl(PairAccountServlet.MISSING_CLIENT_ID_PARAMETER_NAME);
71         }
72         clientId = clientId.strip();
73
74         if (clientSecret == null || clientSecret.isEmpty()) {
75             logger.warn("Request is missing client secret.");
76             return getErrorRedirectionUrl(PairAccountServlet.MISSING_CLIENT_SECRET_PARAMETER_NAME);
77         }
78         clientSecret = clientSecret.strip();
79
80         if (bridgeId == null || bridgeId.isEmpty()) {
81             logger.warn("Request is missing bridge ID.");
82             return getErrorRedirectionUrl(PairAccountServlet.MISSING_BRIDGE_ID_PARAMETER_NAME);
83         }
84         bridgeId = bridgeId.strip();
85
86         if (email == null || email.isEmpty()) {
87             logger.warn("Request is missing e-mail address.");
88             return getErrorRedirectionUrl(PairAccountServlet.MISSING_EMAIL_PARAMETER_NAME);
89         }
90         email = email.strip();
91
92         ThingUID bridgeUid = null;
93         try {
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);
98         }
99
100         try {
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());
105         }
106
107         StringBuffer requestUrl = request.getRequestURL();
108         if (requestUrl == null) {
109             return getErrorRedirectionUrl(PairAccountServlet.MISSING_REQUEST_URL_PARAMETER_NAME);
110         }
111
112         try {
113             return authorizationHandler.getAuthorizationUrl(deriveRedirectUri(requestUrl.toString()));
114         } catch (NoOngoingAuthorizationException e) {
115             logger.warn(
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);
121         }
122     }
123
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);
129         }
130
131         long minutesUntilExpiry = ChronoUnit.MINUTES.between(LocalDateTime.now(), ongoingAuthorizationExpiryTimestamp)
132                 + 1;
133         return getErrorRedirectionUrl(
134                 PairAccountServlet.ONGOING_AUTHORIZATION_IN_STEP1_EXPIRES_IN_MINUTES_PARAMETER_NAME,
135                 Long.toString(minutesUntilExpiry));
136     }
137
138     private String getErrorRedirectionUrl(String errorCode) {
139         return getErrorRedirectionUrl(errorCode, "true");
140     }
141
142     private String getErrorRedirectionUrl(String errorCode, String parameterValue) {
143         return "/mielecloud/pair?" + errorCode + "=" + parameterValue;
144     }
145
146     private String deriveRedirectUri(String requestUrl) {
147         return requestUrl + "/../result";
148     }
149 }