d1a3b19ba4c62289bbdb9a190266681961b25b2d
[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.locator.SingleEndpointLocator;
38 import org.onap.aaf.cadi.lur.ConfigPrincipal;
39
40 import aaf.v2_0.CredRequest;
41
42 public class AAFAuthn<CLIENT> extends AbsUserCache<AAFPermission> {
43     private AAFCon<CLIENT> con;
44     private String realm;
45
46     /**
47      * Configure with Standard AAF properties, Stand alone
48      * @param con
49      * @throws Exception ..
50      */
51     // Package on purpose
52     AAFAuthn(AAFCon<CLIENT> con) {
53         super(con.access,con.cleanInterval,con.highCount,con.usageRefreshTriggerCount);
54         this.con = con;
55     }
56
57     /**
58      * Configure with Standard AAF properties, but share the Cache (with AAF Lur)
59      * @param con
60      * @throws Exception
61      */
62     // Package on purpose
63     AAFAuthn(AAFCon<CLIENT> con, AbsUserCache<AAFPermission> cache) {
64         super(cache);
65         this.con = con;
66     }
67
68     /**
69      * Return Native Realm of AAF Instance.
70      *
71      * @return
72      */
73     public String getRealm() {
74         return realm;
75     }
76
77     /**
78      * Returns null if ok, or an Error String;
79      *
80      * Convenience function.  Passes "null" for State object
81      */
82     public String validate(String user, String password) throws IOException {
83         return validate(user,password,null);
84     }
85
86     /**
87      * Returns null if ok, or an Error String;
88      *
89      * For State Object, you may put in HTTPServletRequest or AuthzTrans, if available.  Otherwise,
90      * leave null
91      *
92      * @param user
93      * @param password
94      * @return
95      * @throws IOException
96      * @throws CadiException
97      * @throws Exception
98      */
99     public String validate(String user, String password, Object state) throws IOException {
100         password = access.decrypt(password, false);
101         byte[] bytes = password.getBytes();
102         User<AAFPermission> usr = getUser(user,bytes);
103
104         if (usr != null && !usr.permExpired()) {
105             if (usr.principal==null) {
106                 return "User already denied";
107             } else {
108                 return null; // good
109             }
110         }
111
112         AAFCachedPrincipal cp = new AAFCachedPrincipal(user, bytes, con.userExpires);
113         // Since I've relocated the Validation piece in the Principal, just revalidate, then do Switch
114         // Statement
115         switch(cp.revalidate(state)) {
116             case REVALIDATED:
117                 if (usr!=null) {
118                     usr.principal = cp;
119                 } else {
120                     addUser(new User<AAFPermission>(cp,con.userExpires));
121                 }
122                 return null;
123             case INACCESSIBLE:
124                 return "AAF Inaccessible";
125             case UNVALIDATED:
126                 addUser(new User<AAFPermission>(user,bytes,con.userExpires));
127                 return "user/pass combo invalid for " + user;
128             case DENIED:
129                 return "AAF denies API for " + user;
130             default:
131                 return "AAFAuthn doesn't handle Principal " + user;
132         }
133     }
134
135     private class AAFCachedPrincipal extends ConfigPrincipal implements CachedPrincipal {
136         private long expires;
137         private long timeToLive;
138
139         private AAFCachedPrincipal(String name, byte[] pass, int timeToLive) {
140             super(name,pass);
141             this.timeToLive = timeToLive;
142             expires = timeToLive + System.currentTimeMillis();
143         }
144
145         public Resp revalidate(Object state) {
146             int maxRetries = 15;
147             try { // these SHOULD be an AAFConHttp and a AAFLocator or SingleEndpointLocator objects, but put in a try to be safe
148                 AAFConHttp forceCastCon = (AAFConHttp) con;
149                 if (forceCastCon.hman().loc instanceof SingleEndpointLocator) {
150                     maxRetries = 1; // we cannot retry the single LGW gateway!
151                 } else {
152                     AAFLocator forceCastLoc = (AAFLocator) forceCastCon.hman().loc;
153                     maxRetries = forceCastLoc.maxIters();
154                 }
155             } catch (Exception e) {
156                 access.log(Access.Level.DEBUG, e);
157             }
158             List<URI> attemptedUris = new ArrayList<>();
159             URI thisUri = null;
160             for (int retries = 0;; retries++) {
161                 try {
162                     Miss missed = missed(getName(), getCred());
163                     if (missed == null || missed.mayContinue()) {
164                         CredRequest cr = new CredRequest();
165                         cr.setId(getName());
166                         cr.setPassword(new String(getCred()));
167                         Rcli<CLIENT> client = con.clientIgnoreAlreadyAttempted(attemptedUris);
168                         thisUri = client.getURI();
169                         Future<String> fp = client.readPost("/authn/validate", con.credReqDF, cr);
170                         //Rcli<CLIENT> client = con.client().forUser(con.basicAuth(getName(), new String(getCred())));
171                         //Future<String> fp = client.read(
172                         //        "/authn/basicAuth",
173                         //        "text/plain"
174                         //       );
175                         if (fp.get(con.timeout)) {
176                             expires = System.currentTimeMillis() + timeToLive;
177                             addUser(new User<AAFPermission>(this, timeToLive));
178                             return Resp.REVALIDATED;
179                         } else {
180                             addMiss(getName(), getCred());
181                             return Resp.UNVALIDATED;
182                         }
183                     } else {
184                         return Resp.UNVALIDATED;
185                     }
186                 } catch (Exception e) {
187                     if (thisUri != null)  {
188                         attemptedUris.add(thisUri);
189                     }
190                     con.access.log(e);
191                     if (retries > maxRetries) {
192                         return Resp.INACCESSIBLE;
193                     }
194                 }
195             }
196         }
197
198         public long expires() {
199             return expires;
200         }
201     }
202
203 }