1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.opencastproject.security.urlsigning.provider.impl;
22
23 import org.opencastproject.security.api.SecurityService;
24 import org.opencastproject.security.urlsigning.WowzaResourceStrategyImpl;
25 import org.opencastproject.security.urlsigning.exception.UrlSigningException;
26 import org.opencastproject.security.urlsigning.provider.UrlSigningProvider;
27 import org.opencastproject.urlsigning.common.Policy;
28 import org.opencastproject.urlsigning.common.ResourceStrategy;
29
30 import org.apache.commons.lang3.exception.ExceptionUtils;
31 import org.osgi.service.cm.ManagedService;
32 import org.osgi.service.component.annotations.Component;
33 import org.osgi.service.component.annotations.Reference;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 import java.net.URI;
38 import java.security.MessageDigest;
39 import java.util.Base64;
40 import java.util.Map;
41 import java.util.SortedMap;
42 import java.util.TreeMap;
43
44 @Component(
45 immediate = true,
46 service = { ManagedService.class, UrlSigningProvider.class },
47 property = {
48 "service.description=Wowza Url Signing Provider",
49 "service.pid=org.opencastproject.security.urlsigning.provider.impl.WowzaUrlSigningProvider"
50 }
51 )
52 public class WowzaUrlSigningProvider extends AbstractUrlSigningProvider {
53
54 private static final Logger logger = LoggerFactory.getLogger(WowzaUrlSigningProvider.class);
55
56
57 private ResourceStrategy resourceStrategy = new WowzaResourceStrategyImpl();
58
59 @Override
60 public Logger getLogger() {
61 return logger;
62 }
63
64 @Override
65 public ResourceStrategy getResourceStrategy() {
66 return resourceStrategy;
67 }
68
69 @Override
70 public String toString() {
71 return "Wowza URL Signing Provider";
72 }
73
74
75
76
77
78
79 @Override
80 public String sign(Policy policy) throws UrlSigningException {
81 if (!accepts(policy.getBaseUrl())) {
82 throw UrlSigningException.urlNotSupported();
83 }
84
85 try {
86 URI uri = new URI(policy.getBaseUrl());
87
88
89
90
91
92
93
94 if ("rtmp".equals((uri.getScheme()))) {
95 return super.sign(policy);
96 }
97
98
99 Key key = getKey(policy.getBaseUrl());
100
101 policy.setResourceStrategy(getResourceStrategy());
102
103 if (!key.getSecret().contains("@")) {
104 getLogger().error("Given key not valid. (prefix@secret)");
105
106 throw new Exception("Given key not valid. (prefix@secret)");
107 }
108 String[] wowzaKeyPair = key.getSecret().split("@");
109 String wowzaPrefix = wowzaKeyPair[0];
110 String wowzaSecret = wowzaKeyPair[1];
111
112 String newUri = new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(),
113 addSignutureToRequest(policy, wowzaPrefix, wowzaSecret), null).toString();
114 return newUri;
115 } catch (Exception e) {
116 getLogger().error("Unable to create signed URL because {}", ExceptionUtils.getStackTrace(e));
117 throw new UrlSigningException(e);
118 }
119 }
120
121
122
123
124
125
126
127
128
129
130
131
132
133 private String addSignutureToRequest(Policy policy, String encryptionKeyId, String encryptionKey) throws Exception {
134 final String startTime;
135 final String endTime = Long.toString(policy.getValidUntil().getMillis() / 1000);
136 final String ip;
137
138 String baseUrl = policy.getBaseUrl();
139 URI url = new URI(policy.getBaseUrl());
140 String resource = policy.getResource();
141 if (policy.getClientIpAddress().isPresent()) {
142
143 String ipAux = policy.getClientIpAddress().get().toString();
144 ipAux = ipAux.substring(1, ipAux.length());
145 ip = ipAux;
146 } else {
147 ip = "";
148 }
149
150 if (policy.getValidFrom().isPresent()) {
151 startTime = Long.toString(policy.getValidFrom().get().getMillis() / 1000);
152 } else {
153 startTime = "";
154 }
155
156 String queryStringParameters = new String();
157
158 queryStringParameters += encryptionKeyId + "endtime=" + endTime;
159
160 if (!"".equals(startTime)) {
161 queryStringParameters += "&" + encryptionKeyId + "starttime=" + startTime;
162 }
163
164 if (url.getQuery() != null) {
165 String query = url.getQuery();
166 String[] params = query.split("&");
167 for (String param : params) {
168 if (param.contains("=")) {
169 String[] keyValue = param.split("=");
170 queryStringParameters += "&" + encryptionKeyId + keyValue[0] + "=" + keyValue[1];
171 }
172 }
173 }
174
175 queryStringParameters += "&" + encryptionKeyId + "hash=" + generateHash(baseUrl,
176 resource, ip, encryptionKeyId, encryptionKey, startTime, endTime);
177
178 return queryStringParameters;
179 }
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200 private String generateHash(String baseUrl, String resource, String ip,
201 String encryptionKeyId, String encryptionKey, String startTime, String endTime) throws Exception {
202 String urlToHash = resource + "?";
203
204 if (!"".equals(ip)) {
205 urlToHash += ip + "&" + encryptionKey;
206 } else {
207 urlToHash += encryptionKey;
208 }
209
210 SortedMap<String, String> arguments = new TreeMap<>();
211
212 arguments.put(encryptionKeyId + "endtime", endTime);
213
214 if (!"".equals(startTime)) {
215 arguments.put(encryptionKeyId + "starttime", startTime);
216 }
217
218 String query = new URI(baseUrl).getQuery();
219 if (null == query) {
220 query = "";
221 }
222
223 String[] params = query.split("&");
224 for (String param : params) {
225 if (param.contains("=")) {
226 String[] keyValue = param.split("=");
227 arguments.put(encryptionKeyId + keyValue[0], keyValue[1]);
228 }
229 }
230
231 for (Map.Entry<String,String> entry : arguments.entrySet()) {
232 String value = entry.getValue();
233 String key = entry.getKey();
234 urlToHash += "&" + key + "=" + value;
235 }
236
237 MessageDigest md = MessageDigest.getInstance("SHA-256");
238 byte[] messageDigest = md.digest(urlToHash.getBytes());
239 String base64Hash = Base64.getEncoder().encodeToString(messageDigest);
240
241 base64Hash = base64Hash.replaceAll("\\+", "-");
242 base64Hash = base64Hash.replaceAll("/", "_");
243
244 return base64Hash;
245 }
246
247 @Reference
248 @Override
249 public void setSecurityService(SecurityService securityService) {
250 super.setSecurityService(securityService);
251 }
252
253 }