]> git.basschouten.com Git - openhab-addons.git/blob
c0b86e903946bcb6e3470bd78728b97205a8e085
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 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.zoneminder.internal.handler;
14
15 import java.net.URLEncoder;
16 import java.nio.charset.StandardCharsets;
17
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.eclipse.jdt.annotation.Nullable;
20 import org.openhab.binding.zoneminder.internal.dto.AuthResponseDTO;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 import com.google.gson.Gson;
25
26 /**
27  * The {@link ZmAuth} manages the authentication process when Zoneminder
28  * authentication is enabled. This class requests access and refresh tokens based
29  * on the expiration times provided by the Zoneminder server.
30  *
31  * @author Mark Hilbush - Initial contribution
32  */
33 @NonNullByDefault
34 public class ZmAuth {
35
36     private final Logger logger = LoggerFactory.getLogger(ZmAuth.class);
37
38     private final ZmBridgeHandler bridgeHandler;
39     private final String authContent;
40     private final boolean usingAuthorization;
41     private boolean isAuthorized;
42
43     private @Nullable String refreshToken;
44     private long refreshTokenExpiresAt;
45     private @Nullable String accessToken;
46     private long accessTokenExpiresAt;
47
48     public ZmAuth(ZmBridgeHandler handler) {
49         this(handler, null, null);
50     }
51
52     public ZmAuth(ZmBridgeHandler handler, @Nullable String user, @Nullable String pass) {
53         this.bridgeHandler = handler;
54         if (user == null || pass == null) {
55             logger.debug("ZmAuth: Authorization is disabled");
56             usingAuthorization = false;
57             isAuthorized = true;
58             authContent = "";
59         } else {
60             logger.debug("ZmAuth: Authorization is enabled");
61             usingAuthorization = true;
62             isAuthorized = false;
63             String encodedUser = URLEncoder.encode(user, StandardCharsets.UTF_8);
64             String encodedPass = URLEncoder.encode(pass, StandardCharsets.UTF_8);
65             authContent = encodedUser == null ? ""
66                     : String.format("user=%s&pass=%s&stateful=1", encodedUser, encodedPass);
67         }
68     }
69
70     public String getAccessToken() {
71         String localAccessToken = accessToken;
72         return localAccessToken != null ? localAccessToken : "";
73     }
74
75     public boolean usingAuthorization() {
76         return usingAuthorization;
77     }
78
79     public boolean isAuthorized() {
80         if (usingAuthorization()) {
81             checkTokens();
82         }
83         return isAuthorized;
84     }
85
86     private void checkTokens() {
87         if (isExpired(refreshTokenExpiresAt)) {
88             getNewRefreshToken();
89         } else if (isExpired(accessTokenExpiresAt)) {
90             getNewAccessToken();
91         }
92     }
93
94     @SuppressWarnings("null")
95     private synchronized void getNewRefreshToken() {
96         // First check to see if another thread has updated it
97         if (!isExpired(refreshTokenExpiresAt)) {
98             return;
99         }
100         String url = bridgeHandler.buildLoginUrl();
101         logger.debug("ZmAuth: Update expired REFRESH token using url '{}'", url);
102         String response = bridgeHandler.executePost(url, authContent, "application/x-www-form-urlencoded");
103         if (response != null) {
104             Gson gson = bridgeHandler.getGson();
105             AuthResponseDTO auth = gson.fromJson(response, AuthResponseDTO.class);
106             if (auth != null && auth.exception == null && auth.refreshToken != null && auth.accessToken != null) {
107                 updateRefreshToken(auth);
108                 updateAccessToken(auth);
109                 isAuthorized = true;
110                 return;
111             }
112         }
113         isAuthorized = false;
114     }
115
116     @SuppressWarnings("null")
117     private synchronized void getNewAccessToken() {
118         // First check to see if another thread has updated it
119         if (!isExpired(accessTokenExpiresAt)) {
120             return;
121         }
122         String url = bridgeHandler.buildLoginUrl(String.format("?token=%s", refreshToken));
123         logger.debug("ZmAuth: Update expired ACCESS token using url '{}'", url);
124         String response = bridgeHandler.executeGet(url);
125         if (response != null) {
126             Gson gson = bridgeHandler.getGson();
127             AuthResponseDTO auth = gson.fromJson(response, AuthResponseDTO.class);
128             if (auth != null && auth.exception == null && auth.accessToken != null) {
129                 updateAccessToken(auth);
130                 isAuthorized = true;
131                 return;
132             }
133         }
134         isAuthorized = false;
135     }
136
137     private void updateAccessToken(AuthResponseDTO auth) {
138         accessToken = auth.accessToken;
139         accessTokenExpiresAt = getExpiresAt(auth.accessTokenExpires);
140         logger.trace("ZmAuth: New access token:  {}", accessToken);
141         logger.trace("ZmAuth: New access token expires in {} sec", getExpiresIn(accessTokenExpiresAt));
142     }
143
144     private void updateRefreshToken(AuthResponseDTO auth) {
145         refreshToken = auth.refreshToken;
146         refreshTokenExpiresAt = getExpiresAt(auth.refreshTokenExpires);
147         logger.trace("ZmAuth: New refresh token: {}", refreshToken);
148         logger.trace("ZmAuth: New refresh token expires in {} sec", getExpiresIn(refreshTokenExpiresAt));
149     }
150
151     private boolean isExpired(long expiresAt) {
152         return (System.currentTimeMillis() / 1000) > expiresAt;
153     }
154
155     private long getExpiresAt(String expiresInSeconds) {
156         try {
157             return (System.currentTimeMillis() / 1000) + (Integer.parseInt(expiresInSeconds) - 300);
158         } catch (NumberFormatException e) {
159             return 0;
160         }
161     }
162
163     private long getExpiresIn(long expiresAtSeconds) {
164         return expiresAtSeconds - (System.currentTimeMillis() / 1000);
165     }
166 }