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