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