[AAF-21] Initial code import
[aaf/cadi.git] / aaf / src / main / java / com / att / cadi / aaf / v2_0 / AAFAuthn.java
1 /*******************************************************************************\r
2  * ============LICENSE_START====================================================\r
3  * * org.onap.aai\r
4  * * ===========================================================================\r
5  * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
6  * * Copyright © 2017 Amdocs\r
7  * * ===========================================================================\r
8  * * Licensed under the Apache License, Version 2.0 (the "License");\r
9  * * you may not use this file except in compliance with the License.\r
10  * * You may obtain a copy of the License at\r
11  * * \r
12  *  *      http://www.apache.org/licenses/LICENSE-2.0\r
13  * * \r
14  *  * Unless required by applicable law or agreed to in writing, software\r
15  * * distributed under the License is distributed on an "AS IS" BASIS,\r
16  * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
17  * * See the License for the specific language governing permissions and\r
18  * * limitations under the License.\r
19  * * ============LICENSE_END====================================================\r
20  * *\r
21  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
22  * *\r
23  ******************************************************************************/\r
24 package com.att.cadi.aaf.v2_0;\r
25 \r
26 import java.io.IOException;\r
27 \r
28 import com.att.aft.dme2.api.DME2Exception;\r
29 import com.att.cadi.AbsUserCache;\r
30 import com.att.cadi.CachedPrincipal;\r
31 import com.att.cadi.CadiException;\r
32 import com.att.cadi.GetCred;\r
33 import com.att.cadi.Hash;\r
34 import com.att.cadi.User;\r
35 import com.att.cadi.aaf.AAFPermission;\r
36 import com.att.cadi.client.Future;\r
37 import com.att.cadi.client.Rcli;\r
38 import com.att.cadi.config.Config;\r
39 import com.att.cadi.lur.ConfigPrincipal;\r
40 import com.att.inno.env.APIException;\r
41 \r
42 public class AAFAuthn<CLIENT> extends AbsUserCache<AAFPermission> {\r
43         private AAFCon<CLIENT> con;\r
44         private String realm;\r
45         \r
46         /**\r
47          * Configure with Standard AAF properties, Stand alone\r
48          * @param con\r
49          * @throws Exception \r
50          */\r
51         // Package on purpose\r
52         AAFAuthn(AAFCon<CLIENT> con) throws Exception {\r
53                 super(con.access,con.cleanInterval,con.highCount,con.usageRefreshTriggerCount);\r
54                 this.con = con;\r
55 \r
56                 try {\r
57                         setRealm();\r
58                 } catch (APIException e) {\r
59                         if(e.getCause() instanceof DME2Exception) {\r
60                                 // Can't contact AAF, assume default\r
61                                 realm=con.access.getProperty(Config.AAF_DEFAULT_REALM, Config.getDefaultRealm());\r
62                         }\r
63                 }\r
64                 }\r
65 \r
66         /**\r
67          * Configure with Standard AAF properties, but share the Cache (with AAF Lur)\r
68          * @param con\r
69          * @throws Exception \r
70          */\r
71         // Package on purpose\r
72         AAFAuthn(AAFCon<CLIENT> con, AbsUserCache<AAFPermission> cache) throws Exception {\r
73                 super(cache);\r
74                 this.con = con;\r
75                 try {\r
76                         setRealm();\r
77                 } catch (Exception e) {\r
78                         if(e.getCause() instanceof DME2Exception) {\r
79                                 access.log(e);\r
80                                 // Can't contact AAF, assume default            \r
81                                 realm=con.access.getProperty(Config.AAF_DEFAULT_REALM, Config.getDefaultRealm());\r
82                         }\r
83                 }\r
84         }\r
85 \r
86         private void setRealm() throws Exception {\r
87                 // Make a call without security set to get the 401 response, which\r
88                 // includes the Realm of the server\r
89                 // This also checks on Connectivity early on.\r
90                 Future<String> fp = con.client(AAFCon.AAF_LATEST_VERSION).read("/authn/basicAuth", "text/plain");\r
91                 if(fp.get(con.timeout)) {\r
92                         throw new Exception("Do not preset Basic Auth Information for AAFAuthn");\r
93                 } else {\r
94                         if(fp.code()==401) {\r
95                                 realm = fp.header("WWW-Authenticate");\r
96                                 if(realm!=null && realm.startsWith("Basic realm=\"")) {\r
97                                         realm = realm.substring(13, realm.length()-1);\r
98                                 } else {\r
99                                         realm = "unknown.com";\r
100                                 }\r
101                         }\r
102                 }\r
103         }\r
104         \r
105         /**\r
106          * Return Native Realm of AAF Instance.\r
107          * \r
108          * @return\r
109          */\r
110         public String getRealm() {\r
111                 return realm;\r
112         }\r
113 \r
114         /**\r
115          * Returns null if ok, or an Error String;\r
116          * \r
117          * @param user\r
118          * @param password\r
119          * @return\r
120          * @throws IOException \r
121          * @throws CadiException \r
122          * @throws Exception\r
123          */\r
124         public String validate(String user, String password) throws IOException, CadiException {\r
125                 User<AAFPermission> usr = getUser(user);\r
126                 if(password.startsWith("enc:???")) {\r
127                         password = access.decrypt(password, true);\r
128                 }\r
129 \r
130                 byte[] bytes = password.getBytes();\r
131                 if(usr != null && usr.principal != null && usr.principal.getName().equals(user) \r
132                                 && usr.principal instanceof GetCred) {\r
133                         \r
134                         if(Hash.isEqual(((GetCred)usr.principal).getCred(),bytes)) {\r
135                                 return null;\r
136                         } else {\r
137                                 remove(usr);\r
138                                 usr = null;\r
139                         }\r
140                 }\r
141                 \r
142                 AAFCachedPrincipal cp = new AAFCachedPrincipal(this,con.app, user, bytes, con.cleanInterval);\r
143                 // Since I've relocated the Validation piece in the Principal, just revalidate, then do Switch\r
144                 // Statement\r
145                 switch(cp.revalidate()) {\r
146                         case REVALIDATED:\r
147                                 if(usr!=null) {\r
148                                         usr.principal = cp;\r
149                                 } else {\r
150                                         addUser(new User<AAFPermission>(cp,con.timeout));\r
151                                 }\r
152                                 return null;\r
153                         case INACCESSIBLE:\r
154                                 return "AAF Inaccessible";\r
155                         case UNVALIDATED:\r
156                                 return "User/Pass combo invalid for " + user;\r
157                         case DENIED:\r
158                                 return "AAF denies API for " + user;\r
159                         default: \r
160                                 return "AAFAuthn doesn't handle Principal " + user;\r
161                 }\r
162         }\r
163         \r
164         private class AAFCachedPrincipal extends ConfigPrincipal implements CachedPrincipal {\r
165                 private long expires,timeToLive;\r
166 \r
167                 public AAFCachedPrincipal(AAFAuthn<?> aaf, String app, String name, byte[] pass, int timeToLive) {\r
168                         super(name,pass);\r
169                         this.timeToLive = timeToLive;\r
170                         expires = timeToLive + System.currentTimeMillis();\r
171                 }\r
172 \r
173                 public Resp revalidate() {\r
174                         if(con.isDisabled()) {\r
175                                 return Resp.DENIED;\r
176                         }\r
177                         try {\r
178                                 Miss missed = missed(getName());\r
179                                 if(missed==null || missed.mayContinue(getCred())) {\r
180                                         Rcli<CLIENT> client = con.client(AAFCon.AAF_LATEST_VERSION).forUser(con.basicAuth(getName(), new String(getCred())));\r
181                                         Future<String> fp = client.read(\r
182                                                         "/authn/basicAuth",\r
183                                                         "text/plain"\r
184                                                         );\r
185                                         if(fp.get(con.timeout)) {\r
186                                                 expires = System.currentTimeMillis() + timeToLive;\r
187                                                 addUser(new User<AAFPermission>(this, expires));\r
188                                                 return Resp.REVALIDATED;\r
189                                         } else {\r
190                                                 addMiss(getName(), getCred());\r
191                                                 return Resp.UNVALIDATED;\r
192                                         }\r
193                                 } else {\r
194                                         return Resp.UNVALIDATED;\r
195                                 }\r
196                         } catch (Exception e) {\r
197                                 con.access.log(e);\r
198                                 return Resp.INACCESSIBLE;\r
199                         }\r
200                 }\r
201 \r
202                 public long expires() {\r
203                         return expires;\r
204                 }\r
205         };\r
206 \r
207 }\r