0c72dcda332d31de459b2816b6407642c1f16331
[aaf/cadi.git] / aaf / src / 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 com.att.aft.dme2.api.DME2Exception;\r
27 import com.att.cadi.AbsUserCache;\r
28 import com.att.cadi.CachedPrincipal;\r
29 import com.att.cadi.GetCred;\r
30 import com.att.cadi.Hash;\r
31 import com.att.cadi.User;\r
32 import com.att.cadi.aaf.AAFPermission;\r
33 import com.att.cadi.client.Future;\r
34 import com.att.cadi.client.Rcli;\r
35 import com.att.cadi.config.Config;\r
36 import com.att.cadi.lur.ConfigPrincipal;\r
37 import com.att.inno.env.APIException;\r
38 \r
39 public class AAFAuthn<CLIENT> extends AbsUserCache<AAFPermission> {\r
40         private AAFCon<CLIENT> con;\r
41         private String realm;\r
42         \r
43         /**\r
44          * Configure with Standard AAF properties, Stand alone\r
45          * @param con\r
46          * @throws Exception \r
47          */\r
48         // Package on purpose\r
49         AAFAuthn(AAFCon<CLIENT> con) throws Exception {\r
50                 super(con.access,con.cleanInterval,con.highCount,con.usageRefreshTriggerCount);\r
51                 this.con = con;\r
52 \r
53                 try {\r
54                         setRealm();\r
55                 } catch (APIException e) {\r
56                         if(e.getCause() instanceof DME2Exception) {\r
57                                 // Can't contact AAF, assume default\r
58                                 realm=con.access.getProperty(Config.AAF_DEFAULT_REALM, Config.getDefaultRealm());\r
59                         }\r
60                 }\r
61                 }\r
62 \r
63         /**\r
64          * Configure with Standard AAF properties, but share the Cache (with AAF Lur)\r
65          * @param con\r
66          * @throws Exception \r
67          */\r
68         // Package on purpose\r
69         AAFAuthn(AAFCon<CLIENT> con, AbsUserCache<AAFPermission> cache) throws Exception {\r
70                 super(cache);\r
71                 this.con = con;\r
72                 try {\r
73                         setRealm();\r
74                 } catch (Exception e) {\r
75                         if(e.getCause() instanceof DME2Exception) {\r
76                                 access.log(e);\r
77                                 // Can't contact AAF, assume default            \r
78                                 realm=con.access.getProperty(Config.AAF_DEFAULT_REALM, Config.getDefaultRealm());\r
79                         }\r
80                 }\r
81         }\r
82 \r
83         private void setRealm() throws Exception {\r
84                 // Make a call without security set to get the 401 response, which\r
85                 // includes the Realm of the server\r
86                 // This also checks on Connectivity early on.\r
87                 Future<String> fp = con.client(AAFCon.AAF_VERSION).read("/authn/basicAuth", "text/plain");\r
88                 if(fp.get(con.timeout)) {\r
89                         throw new Exception("Do not preset Basic Auth Information for AAFAuthn");\r
90                 } else {\r
91                         if(fp.code()==401) {\r
92                                 realm = fp.header("WWW-Authenticate");\r
93                                 if(realm!=null && realm.startsWith("Basic realm=\"")) {\r
94                                         realm = realm.substring(13, realm.length()-1);\r
95                                 } else {\r
96                                         realm = "unknown.com";\r
97                                 }\r
98                         }\r
99                 }\r
100         }\r
101         \r
102         /**\r
103          * Return Native Realm of AAF Instance.\r
104          * \r
105          * @return\r
106          */\r
107         public String getRealm() {\r
108                 return realm;\r
109         }\r
110 \r
111         /**\r
112          * Returns null if ok, or an Error String;\r
113          * \r
114          * @param user\r
115          * @param password\r
116          * @return\r
117          * @throws Exception\r
118          */\r
119         public String validate(String user, String password) throws Exception {\r
120                 User<AAFPermission> usr = getUser(user);\r
121                 if(password.startsWith("enc:???")) {\r
122                         password = access.decrypt(password, true);\r
123                 }\r
124 \r
125                 byte[] bytes = password.getBytes();\r
126                 if(usr != null && usr.principal != null && usr.principal.getName().equals(user) \r
127                                 && usr.principal instanceof GetCred) {\r
128                         \r
129                         if(Hash.isEqual(((GetCred)usr.principal).getCred(),bytes)) {\r
130                                 return null;\r
131                         } else {\r
132                                 remove(usr);\r
133                                 usr = null;\r
134                         }\r
135                 }\r
136                 \r
137                 AAFCachedPrincipal cp = new AAFCachedPrincipal(this,con.app, user, bytes, con.cleanInterval);\r
138                 // Since I've relocated the Validation piece in the Principal, just revalidate, then do Switch\r
139                 // Statement\r
140                 switch(cp.revalidate()) {\r
141                         case REVALIDATED:\r
142                                 if(usr!=null) {\r
143                                         usr.principal = cp;\r
144                                 } else {\r
145                                         addUser(new User<AAFPermission>(cp,con.timeout));\r
146                                 }\r
147                                 return null;\r
148                         case INACCESSIBLE:\r
149                                 return "AAF Inaccessible";\r
150                         case UNVALIDATED:\r
151                                 return "User/Pass combo invalid";\r
152                         default: \r
153                                 return "AAFAuthn doesn't handle this Principal";\r
154                 }\r
155         }\r
156         \r
157         private class AAFCachedPrincipal extends ConfigPrincipal implements CachedPrincipal {\r
158                 private long expires,timeToLive;\r
159 \r
160                 public AAFCachedPrincipal(AAFAuthn<?> aaf, String app, String name, byte[] pass, int timeToLive) {\r
161                         super(name,pass);\r
162                         this.timeToLive = timeToLive;\r
163                         expires = timeToLive + System.currentTimeMillis();\r
164                 }\r
165 \r
166                 public Resp revalidate() {\r
167                         try {\r
168                                 Miss missed = missed(getName());\r
169                                 if(missed==null || missed.mayContinue(getCred())) {\r
170                                         Rcli<CLIENT> client = con.client(AAFCon.AAF_VERSION).forUser(con.basicAuth(getName(), new String(getCred())));\r
171                                         Future<String> fp = client.read(\r
172                                                         "/authn/basicAuth",\r
173                                                         "text/plain"\r
174                                                         );\r
175                                         if(fp.get(con.timeout)) {\r
176                                                 expires = System.currentTimeMillis() + timeToLive;\r
177                                                 addUser(new User<AAFPermission>(this, expires));\r
178                                                 return Resp.REVALIDATED;\r
179                                         } else {\r
180                                                 addMiss(getName(), getCred());\r
181                                                 return Resp.UNVALIDATED;\r
182                                         }\r
183                                 } else {\r
184                                         return Resp.UNVALIDATED;\r
185                                 }\r
186                         } catch (Exception e) {\r
187                                 con.access.log(e);\r
188                                 return Resp.INACCESSIBLE;\r
189                         }\r
190                 }\r
191 \r
192                 public long expires() {\r
193                         return expires;\r
194                 }\r
195         };\r
196 \r
197 }\r