]> git.basschouten.com Git - openhab-addons.git/blob
e817463adf87db2ad3786773d91f3571d4de46aa
[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         if (clientSecret == null || clientSecret.isEmpty()) {
74             logger.warn("Request is missing client secret.");
75             return getErrorRedirectionUrl(PairAccountServlet.MISSING_CLIENT_SECRET_PARAMETER_NAME);
76         }
77         if (bridgeId == null || bridgeId.isEmpty()) {
78             logger.warn("Request is missing bridge ID.");
79             return getErrorRedirectionUrl(PairAccountServlet.MISSING_BRIDGE_ID_PARAMETER_NAME);
80         }
81         if (email == null || email.isEmpty()) {
82             logger.warn("Request is missing e-mail address.");
83             return getErrorRedirectionUrl(PairAccountServlet.MISSING_EMAIL_PARAMETER_NAME);
84         }
85
86         ThingUID bridgeUid = null;
87         try {
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);
92         }
93
94         if (!EmailValidator.isValid(email)) {
95             logger.warn("Passed e-mail address '{}' is invalid.", email);
96             return getErrorRedirectionUrl(PairAccountServlet.MALFORMED_EMAIL_PARAMETER_NAME);
97         }
98
99         try {
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());
104         }
105
106         StringBuffer requestUrl = request.getRequestURL();
107         if (requestUrl == null) {
108             return getErrorRedirectionUrl(PairAccountServlet.MISSING_REQUEST_URL_PARAMETER_NAME);
109         }
110
111         try {
112             return authorizationHandler.getAuthorizationUrl(deriveRedirectUri(requestUrl.toString()));
113         } catch (NoOngoingAuthorizationException e) {
114             logger.warn(
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);
120         }
121     }
122
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);
128         }
129
130         long minutesUntilExpiry = ChronoUnit.MINUTES.between(LocalDateTime.now(), ongoingAuthorizationExpiryTimestamp)
131                 + 1;
132         return getErrorRedirectionUrl(
133                 PairAccountServlet.ONGOING_AUTHORIZATION_IN_STEP1_EXPIRES_IN_MINUTES_PARAMETER_NAME,
134                 Long.toString(minutesUntilExpiry));
135     }
136
137     private String getErrorRedirectionUrl(String errorCode) {
138         return getErrorRedirectionUrl(errorCode, "true");
139     }
140
141     private String getErrorRedirectionUrl(String errorCode, String parameterValue) {
142         return "/mielecloud/pair?" + errorCode + "=" + parameterValue;
143     }
144
145     private String deriveRedirectUri(String requestUrl) {
146         return requestUrl + "/../result";
147     }
148 }