]> git.basschouten.com Git - openhab-addons.git/blob
aa419fb41e963cd241286897801d0cd105dce078
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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.binding.mielecloud.internal.util.EmailValidator;
28 import org.openhab.core.thing.ThingUID;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 /**
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.
37  *
38  * @author Björn Lange - Initial Contribution
39  */
40 @NonNullByDefault
41 public final class ForwardToLoginServlet extends AbstractRedirectionServlet {
42     private static final long serialVersionUID = -9094642228439994183L;
43
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";
48
49     private final Logger logger = LoggerFactory.getLogger(ForwardToLoginServlet.class);
50
51     private final OAuthAuthorizationHandler authorizationHandler;
52
53     /**
54      * Creates a new {@link ForwardToLoginServlet}.
55      *
56      * @param authorizationHandler Handler implementing the OAuth authorization process.
57      */
58     public ForwardToLoginServlet(OAuthAuthorizationHandler authorizationHandler) {
59         this.authorizationHandler = authorizationHandler;
60     }
61
62     @Override
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);
68
69         if (clientId == null || clientId.isEmpty()) {
70             logger.warn("Request is missing client ID.");
71             return getErrorRedirectionUrl(PairAccountServlet.MISSING_CLIENT_ID_PARAMETER_NAME);
72         }
73         clientId = clientId.strip();
74
75         if (clientSecret == null || clientSecret.isEmpty()) {
76             logger.warn("Request is missing client secret.");
77             return getErrorRedirectionUrl(PairAccountServlet.MISSING_CLIENT_SECRET_PARAMETER_NAME);
78         }
79         clientSecret = clientSecret.strip();
80
81         if (bridgeId == null || bridgeId.isEmpty()) {
82             logger.warn("Request is missing bridge ID.");
83             return getErrorRedirectionUrl(PairAccountServlet.MISSING_BRIDGE_ID_PARAMETER_NAME);
84         }
85         bridgeId = bridgeId.strip();
86
87         if (email == null || email.isEmpty()) {
88             logger.warn("Request is missing e-mail address.");
89             return getErrorRedirectionUrl(PairAccountServlet.MISSING_EMAIL_PARAMETER_NAME);
90         }
91         email = email.strip();
92
93         ThingUID bridgeUid = null;
94         try {
95             bridgeUid = new ThingUID(MieleCloudBindingConstants.THING_TYPE_BRIDGE, bridgeId);
96         } catch (IllegalArgumentException e) {
97             logger.warn("Passed bridge ID '{}' is invalid.", bridgeId);
98             return getErrorRedirectionUrl(PairAccountServlet.MALFORMED_BRIDGE_ID_PARAMETER_NAME);
99         }
100
101         if (!EmailValidator.isValid(email)) {
102             logger.warn("Passed e-mail address '{}' is invalid.", email);
103             return getErrorRedirectionUrl(PairAccountServlet.MALFORMED_EMAIL_PARAMETER_NAME);
104         }
105
106         try {
107             authorizationHandler.beginAuthorization(clientId, clientSecret, bridgeUid, email);
108         } catch (OngoingAuthorizationException e) {
109             logger.warn("Cannot begin new authorization process while another one is still running.");
110             return getErrorRedirectUrlWithExpiryTime(e.getOngoingAuthorizationExpiryTimestamp());
111         }
112
113         StringBuffer requestUrl = request.getRequestURL();
114         if (requestUrl == null) {
115             return getErrorRedirectionUrl(PairAccountServlet.MISSING_REQUEST_URL_PARAMETER_NAME);
116         }
117
118         try {
119             return authorizationHandler.getAuthorizationUrl(deriveRedirectUri(requestUrl.toString()));
120         } catch (NoOngoingAuthorizationException e) {
121             logger.warn(
122                     "Failed to create authorization URL: There was no ongoing authorization although we just started one.");
123             return getErrorRedirectionUrl(PairAccountServlet.NO_ONGOING_AUTHORIZATION_IN_STEP2_PARAMETER_NAME);
124         } catch (OAuthException e) {
125             logger.warn("Failed to create authorization URL.", e);
126             return getErrorRedirectionUrl(PairAccountServlet.FAILED_TO_DERIVE_REDIRECT_URL_PARAMETER_NAME);
127         }
128     }
129
130     private String getErrorRedirectUrlWithExpiryTime(@Nullable LocalDateTime ongoingAuthorizationExpiryTimestamp) {
131         if (ongoingAuthorizationExpiryTimestamp == null) {
132             return getErrorRedirectionUrl(
133                     PairAccountServlet.ONGOING_AUTHORIZATION_IN_STEP1_EXPIRES_IN_MINUTES_PARAMETER_NAME,
134                     PairAccountServlet.ONGOING_AUTHORIZATION_UNKNOWN_EXPIRY_TIME);
135         }
136
137         long minutesUntilExpiry = ChronoUnit.MINUTES.between(LocalDateTime.now(), ongoingAuthorizationExpiryTimestamp)
138                 + 1;
139         return getErrorRedirectionUrl(
140                 PairAccountServlet.ONGOING_AUTHORIZATION_IN_STEP1_EXPIRES_IN_MINUTES_PARAMETER_NAME,
141                 Long.toString(minutesUntilExpiry));
142     }
143
144     private String getErrorRedirectionUrl(String errorCode) {
145         return getErrorRedirectionUrl(errorCode, "true");
146     }
147
148     private String getErrorRedirectionUrl(String errorCode, String parameterValue) {
149         return "/mielecloud/pair?" + errorCode + "=" + parameterValue;
150     }
151
152     private String deriveRedirectUri(String requestUrl) {
153         return requestUrl + "/../result";
154     }
155 }