Create and prepare non-deploy release 2.7.1
[aaf/authz.git] / cadi / aaf / src / main / java / org / onap / aaf / cadi / aaf / v2_0 / AAFAuthn.java
1 /**
2  * ============LICENSE_START====================================================
3  * org.onap.aaf
4  * ===========================================================================
5  * Copyright (c) 2018 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  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END====================================================
19  *
20  */
21
22 package org.onap.aaf.cadi.aaf.v2_0;
23
24 import java.io.IOException;
25 import java.net.URI;
26 import java.util.ArrayList;
27 import java.util.List;
28
29 import org.onap.aaf.cadi.AbsUserCache;
30 import org.onap.aaf.cadi.Access;
31 import org.onap.aaf.cadi.CachedPrincipal;
32 import org.onap.aaf.cadi.CadiException;
33 import org.onap.aaf.cadi.User;
34 import org.onap.aaf.cadi.aaf.AAFPermission;
35 import org.onap.aaf.cadi.client.Future;
36 import org.onap.aaf.cadi.client.Rcli;
37 import org.onap.aaf.cadi.lur.ConfigPrincipal;
38
39 import aaf.v2_0.CredRequest;
40
41 public class AAFAuthn<CLIENT> extends AbsUserCache<AAFPermission> {
42     private AAFCon<CLIENT> con;
43     private String realm;
44
45     /**
46      * Configure with Standard AAF properties, Stand alone
47      * @param con
48      * @throws Exception ..
49      */
50     // Package on purpose
51     AAFAuthn(AAFCon<CLIENT> con) {
52         super(con.access,con.cleanInterval,con.highCount,con.usageRefreshTriggerCount);
53         this.con = con;
54     }
55
56     /**
57      * Configure with Standard AAF properties, but share the Cache (with AAF Lur)
58      * @param con
59      * @throws Exception
60      */
61     // Package on purpose
62     AAFAuthn(AAFCon<CLIENT> con, AbsUserCache<AAFPermission> cache) {
63         super(cache);
64         this.con = con;
65     }
66
67     /**
68      * Return Native Realm of AAF Instance.
69      *
70      * @return
71      */
72     public String getRealm() {
73         return realm;
74     }
75
76     /**
77      * Returns null if ok, or an Error String;
78      *
79      * Convenience function.  Passes "null" for State object
80      */
81     public String validate(String user, String password) throws IOException {
82         return validate(user,password,null);
83     }
84
85     /**
86      * Returns null if ok, or an Error String;
87      *
88      * For State Object, you may put in HTTPServletRequest or AuthzTrans, if available.  Otherwise,
89      * leave null
90      *
91      * @param user
92      * @param password
93      * @return
94      * @throws IOException
95      * @throws CadiException
96      * @throws Exception
97      */
98     public String validate(String user, String password, Object state) throws IOException {
99         password = access.decrypt(password, false);
100         byte[] bytes = password.getBytes();
101         User<AAFPermission> usr = getUser(user,bytes);
102
103         if (usr != null && !usr.permExpired()) {
104             if (usr.principal==null) {
105                 return "User already denied";
106             } else {
107                 return null; // good
108             }
109         }
110
111         AAFCachedPrincipal cp = new AAFCachedPrincipal(user, bytes, con.cleanInterval);
112         // Since I've relocated the Validation piece in the Principal, just revalidate, then do Switch
113         // Statement
114         switch(cp.revalidate(state)) {
115             case REVALIDATED:
116                 if (usr!=null) {
117                     usr.principal = cp;
118                 } else {
119                     addUser(new User<AAFPermission>(cp,con.timeout));
120                 }
121                 return null;
122             case INACCESSIBLE:
123                 return "AAF Inaccessible";
124             case UNVALIDATED:
125                 addUser(new User<AAFPermission>(user,bytes,con.timeout));
126                 return "user/pass combo invalid for " + user;
127             case DENIED:
128                 return "AAF denies API for " + user;
129             default:
130                 return "AAFAuthn doesn't handle Principal " + user;
131         }
132     }
133
134     private class AAFCachedPrincipal extends ConfigPrincipal implements CachedPrincipal {
135         private long expires;
136         private long timeToLive;
137
138         private AAFCachedPrincipal(String name, byte[] pass, int timeToLive) {
139             super(name,pass);
140             this.timeToLive = timeToLive;
141             expires = timeToLive + System.currentTimeMillis();
142         }
143
144         public Resp revalidate(Object state) {
145             int maxRetries = 15;
146             try { // these SHOULD be AAFConHttp and AAFLocator objects, but put in a try anyway to be safe
147                 AAFConHttp forceCastCon = (AAFConHttp) con;
148                 AAFLocator forceCastLoc = (AAFLocator) forceCastCon.hman().loc;
149                 maxRetries = forceCastLoc.maxIters();
150             } catch (Exception e) {
151                 access.log(Access.Level.DEBUG, e);
152             }
153             List<URI> attemptedUris = new ArrayList<>();
154             URI thisUri = null;
155             for (int retries = 0;; retries++) {
156                 try {
157                     Miss missed = missed(getName(), getCred());
158                     if (missed == null || missed.mayContinue()) {
159                         CredRequest cr = new CredRequest();
160                         cr.setId(getName());
161                         cr.setPassword(new String(getCred()));
162                         Rcli<CLIENT> client = con.clientIgnoreAlreadyAttempted(attemptedUris);
163                         thisUri = client.getURI();
164                         Future<String> fp = client.readPost("/authn/validate", con.credReqDF, cr);
165                         //Rcli<CLIENT> client = con.client().forUser(con.basicAuth(getName(), new String(getCred())));
166                         //Future<String> fp = client.read(
167                         //        "/authn/basicAuth",
168                         //        "text/plain"
169                         //       );
170                         if (fp.get(con.timeout)) {
171                             expires = System.currentTimeMillis() + timeToLive;
172                             addUser(new User<AAFPermission>(this, expires));
173                             return Resp.REVALIDATED;
174                         } else {
175                             addMiss(getName(), getCred());
176                             return Resp.UNVALIDATED;
177                         }
178                     } else {
179                         return Resp.UNVALIDATED;
180                     }
181                 } catch (Exception e) {
182                     if (thisUri != null)  {
183                         attemptedUris.add(thisUri);
184                     }
185                     con.access.log(e);
186                     if (retries > maxRetries) {
187                         return Resp.INACCESSIBLE;
188                     }
189                 }
190             }
191         }
192
193         public long expires() {
194             return expires;
195         }
196     }
197
198 }