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