DMAAP-MR - Merge MR repos
[dmaap/messagerouter/messageservice.git] / src / main / java / org / onap / dmaap / dmf / mr / security / impl / DMaaPOriginalUebAuthenticator.java
1 /*******************************************************************************
2  *  ============LICENSE_START=======================================================
3  *  org.onap.dmaap
4  *  ================================================================================
5  *  Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6  *  ================================================================================
7  *  Licensed under the Apache License, Version 2.0 (the "License");
8  *  you may not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at
10  *        http://www.apache.org/licenses/LICENSE-2.0
11 *  
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  *  ============LICENSE_END=========================================================
18  *  
19  *  ECOMP is a trademark and service mark of AT&T Intellectual Property.
20  *  
21  *******************************************************************************/
22 package org.onap.dmaap.dmf.mr.security.impl;
23
24 import com.att.eelf.configuration.EELFLogger;
25 import com.att.eelf.configuration.EELFManager;
26 import com.att.nsa.configs.ConfigDbException;
27 import com.att.nsa.drumlin.till.data.sha1HmacSigner;
28 import com.att.nsa.security.NsaApiKey;
29 import com.att.nsa.security.db.NsaApiDb;
30 import org.onap.dmaap.dmf.mr.beans.DMaaPContext;
31 import org.onap.dmaap.dmf.mr.security.DMaaPAuthenticator;
32
33 import javax.servlet.http.HttpServletRequest;
34 import java.text.ParseException;
35 import java.text.SimpleDateFormat;
36 import java.util.Date;
37
38 /**
39  * This authenticator handles an AWS-like authentication, originally used by the
40  * Cambria server (the API server for UEB).
41  * 
42  * @author peter
43  *
44  * @param <K>
45  */
46 public class DMaaPOriginalUebAuthenticator<K extends NsaApiKey> implements DMaaPAuthenticator<K> {
47         /**
48          * constructor initialization
49          * 
50          * @param db
51          * @param requestTimeWindowMs
52          */
53         public DMaaPOriginalUebAuthenticator(NsaApiDb<K> db, long requestTimeWindowMs) {
54                 fDb = db;
55                 fRequestTimeWindowMs = requestTimeWindowMs;
56                 
57
58                 
59
60         }
61
62         @Override
63         public boolean qualify(HttpServletRequest req) {
64                 // accept anything that comes in with X-(Cambria)Auth in the header
65                 final String xAuth = getFirstHeader(req, new String[] { "X-CambriaAuth", "X-Auth" });
66                 return xAuth != null;
67         }
68
69         /**
70          * method for authentication
71          * 
72          * @param req
73          * @return
74          */
75         public K isAuthentic(HttpServletRequest req) {
76                 final String remoteAddr = req.getRemoteAddr();
77                 // Cambria originally used "Cambria..." headers, but as the API key
78                 // system is now more
79                 // general, we take either form.
80                 final String xAuth = getFirstHeader(req, new String[] { "X-CambriaAuth", "X-Auth" });
81                 final String xDate = getFirstHeader(req, new String[] { "X-CambriaDate", "X-Date" });
82
83                 final String httpDate = req.getHeader("Date");
84
85                 final String xNonce = getFirstHeader(req, new String[] { "X-Nonce" });
86                 return authenticate(remoteAddr, xAuth, xDate, httpDate, xNonce);
87         }
88
89         /**
90          * Authenticate a user's request. This method returns the API key if the
91          * user is authentic, null otherwise.
92          * 
93          * @param remoteAddr
94          * @param xAuth
95          * @param xDate
96          * @param httpDate
97          * @param nonce
98          * @return an api key record, or null
99          */
100         public K authenticate(String remoteAddr, String xAuth, String xDate, String httpDate, String nonce) {
101                 if (xAuth == null) {
102                         authLog("No X-Auth header on request", remoteAddr);
103                         return null;
104                 }
105                 
106                 final String[] xAuthParts = xAuth.split(":");
107                 if (xAuthParts.length != 2) {
108                         authLog("Bad X-Auth header format (" + xAuth + ")", remoteAddr);
109                         return null;
110                 }
111
112
113                 // get the api key and signature
114                 final String clientApiKey = xAuthParts[0];
115                 final String clientApiHash = xAuthParts[1];
116                 if (clientApiKey.length() == 0 || clientApiHash.length() == 0) {
117                         authLog("Bad X-Auth header format (" + xAuth + ")", remoteAddr);
118                         return null;
119                 }
120                 // if the user provided X-Date, use that. Otherwise, go for Date
121                 final String dateString = xDate != null ? xDate : httpDate;
122                 final Date clientDate = getClientDate(dateString);
123                 if (clientDate == null) {
124                         authLog("Couldn't parse client date '" + dateString + "'. Preferring X-Date over Date.", remoteAddr);
125                         return null;
126                 }
127                 // check the time range
128                 final long nowMs = System.currentTimeMillis();
129                 final long diffMs = Math.abs(nowMs - clientDate.getTime());
130                 if (diffMs > fRequestTimeWindowMs) {
131                         authLog("Client date is not in acceptable range of server date. Client:" + clientDate.getTime()
132                                         + ", Server: " + nowMs + ", Threshold: " + fRequestTimeWindowMs + ".", remoteAddr);
133                         return null;
134                 }
135                 K apiRecord;
136                 try {
137                         apiRecord = fDb.loadApiKey(clientApiKey);
138                         if (apiRecord == null) {
139                                 authLog("No such API key " + clientApiKey, remoteAddr);
140                                 return null;
141                         }
142                 } catch (ConfigDbException e) {
143                         authLog("Couldn't load API key " + clientApiKey + ": " + e.getMessage(), remoteAddr);
144                         return null;
145                 }
146                                 // make the signed content
147                 final StringBuilder sb = new StringBuilder();
148                 sb.append(dateString);
149                 if (nonce != null) {
150                         sb.append(":");
151                         sb.append(nonce);
152                 }
153                 final String signedContent = sb.toString();
154                 // now check the signed date string
155                 final String serverCalculatedSignature = sha1HmacSigner.sign(signedContent, apiRecord.getSecret());
156                 if (serverCalculatedSignature == null || !serverCalculatedSignature.equals(clientApiHash)) {
157                         authLog("Signatures don't match. Rec'd " + clientApiHash + ", expect " + serverCalculatedSignature + ".",
158                                         remoteAddr);
159                         return null;
160                 }
161                 authLog("authenticated " + apiRecord.getKey(), remoteAddr);
162                 return apiRecord;
163         }
164
165         /**
166          * Get the first value of the first existing header from the headers list
167          * 
168          * @param req
169          * @param headers
170          * @return a header value, or null if none exist
171          */
172         private static String getFirstHeader(HttpServletRequest req, String[] headers) {
173                 for (String header : headers) {
174                         final String result = req.getHeader(header);
175                         if (result != null)
176                                 return result;
177                 }
178                 return null;
179         }
180
181         /**
182          * Parse the date string into a Date using one of the supported date
183          * formats.
184          * 
185          * @param dateHeader
186          * @return a date, or null
187          */
188         private static Date getClientDate(String dateString) {
189                 if (dateString == null) {
190                         return null;
191                 }
192
193                 // parse the date
194                 Date result = null;
195                 for (String dateFormat : kDateFormats) {
196                         final SimpleDateFormat parser = new SimpleDateFormat(dateFormat, java.util.Locale.US);
197                         if (!dateFormat.contains("z") && !dateFormat.contains("Z")) {
198                                 parser.setTimeZone(TIMEZONE_GMT);
199                         }
200
201                         try {
202                                 result = parser.parse(dateString);
203                                 break;
204                         } catch (ParseException e) {
205                                 // presumably wrong format
206                         }
207                 }
208                 return result;
209         }
210
211         private static void authLog(String msg, String remoteAddr) {
212                 log.info("AUTH-LOG(" + remoteAddr + "): " + msg);
213         }
214
215         private final NsaApiDb<K> fDb;
216         private final long fRequestTimeWindowMs;
217
218         private static final java.util.TimeZone TIMEZONE_GMT = java.util.TimeZone.getTimeZone("GMT");
219         
220         private static final String kDateFormats[] =
221                 {
222                     // W3C date format (RFC 3339).
223                     "yyyy-MM-dd'T'HH:mm:ssz",
224                     "yyyy-MM-dd'T'HH:mm:ssXXX",         // as of Java 7, reqd to handle colon in TZ offset
225
226                     // Preferred HTTP date format (RFC 1123).
227                     "EEE, dd MMM yyyy HH:mm:ss zzz",
228
229                     // simple unix command line 'date' format
230                     "EEE MMM dd HH:mm:ss z yyyy",
231
232                     // Common date format (RFC 822).
233                     "EEE, dd MMM yy HH:mm:ss z",
234                     "EEE, dd MMM yy HH:mm z",
235                     "dd MMM yy HH:mm:ss z",
236                     "dd MMM yy HH:mm z",
237
238                         // Obsoleted HTTP date format (ANSI C asctime() format).
239                     "EEE MMM dd HH:mm:ss yyyy",
240
241                     // Obsoleted HTTP date format (RFC 1036).
242                     "EEEE, dd-MMM-yy HH:mm:ss zzz",
243                 };
244
245         
246                         
247                         
248
249                 
250                         
251
252                         
253                         
254
255                         
256                         
257
258                         
259                         
260
261                         
262                         
263         // logger declaration
264         
265         private static final EELFLogger log = EELFManager.getInstance().getLogger(DMaaPOriginalUebAuthenticator.class);
266         @Override
267
268                 // TODO Auto-generated method stub
269                 
270         //}
271         
272         public K authenticate(DMaaPContext ctx) {
273                 
274                 
275                 
276                         
277                                 
278                                 
279                                         
280                         
281                         
282                 
283                 return null;
284         }
285
286
287         public void addAuthenticator ( DMaaPAuthenticator<K> a )
288         {
289                 
290         }
291         
292 }