42f3ec4dc4e6303502665234c16a1e1b31d24490
[aaf/authz.git] / cadi / aaf / src / main / java / org / onap / aaf / cadi / aaf / v2_0 / AAFTaf.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.ConnectException;
26 import java.security.Principal;
27
28 import javax.servlet.http.HttpServletRequest;
29 import javax.servlet.http.HttpServletResponse;
30
31 import org.onap.aaf.cadi.AbsUserCache;
32 import org.onap.aaf.cadi.CachedPrincipal;
33 import org.onap.aaf.cadi.CadiException;
34 import org.onap.aaf.cadi.Connector;
35 import org.onap.aaf.cadi.GetCred;
36 import org.onap.aaf.cadi.Hash;
37 import org.onap.aaf.cadi.SecuritySetter;
38 import org.onap.aaf.cadi.User;
39 import org.onap.aaf.cadi.Access.Level;
40 import org.onap.aaf.cadi.CachedPrincipal.Resp;
41 import org.onap.aaf.cadi.Taf.LifeForm;
42 import org.onap.aaf.cadi.aaf.AAFPermission;
43 import org.onap.aaf.cadi.aaf.v2_0.AAFCon.GetSetter;
44 import org.onap.aaf.cadi.client.Future;
45 import org.onap.aaf.cadi.client.Rcli;
46 import org.onap.aaf.cadi.client.Retryable;
47 import org.onap.aaf.cadi.config.Config;
48 import org.onap.aaf.cadi.principal.BasicPrincipal;
49 import org.onap.aaf.cadi.principal.CachedBasicPrincipal;
50 import org.onap.aaf.cadi.taf.HttpTaf;
51 import org.onap.aaf.cadi.taf.TafResp;
52 import org.onap.aaf.cadi.taf.TafResp.RESP;
53 import org.onap.aaf.cadi.taf.basic.BasicHttpTafResp;
54 import org.onap.aaf.misc.env.APIException;
55
56 public class AAFTaf<CLIENT> extends AbsUserCache<AAFPermission> implements HttpTaf {
57 //      private static final String INVALID_AUTH_TOKEN = "Invalid Auth Token";
58 //      private static final String AUTHENTICATING_SERVICE_UNAVAILABLE = "Authenticating Service unavailable";
59         private AAFCon<CLIENT> aaf;
60         private boolean warn;
61
62         public AAFTaf(AAFCon<CLIENT> con, boolean turnOnWarning) {
63                 super(con.access,con.cleanInterval,con.highCount, con.usageRefreshTriggerCount);
64                 aaf = con;
65                 warn = turnOnWarning;
66         }
67
68         public AAFTaf(AAFCon<CLIENT> con, boolean turnOnWarning, AbsUserCache<AAFPermission> other) {
69                 super(other);
70                 aaf = (AAFCon<CLIENT>)con;
71                 warn = turnOnWarning;
72         }
73         
74         // Note: Needed for Creation of this Object with Generics
75         @SuppressWarnings("unchecked")
76         public AAFTaf(Connector mustBeAAFCon, boolean turnOnWarning, AbsUserCache<AAFPermission> other) throws CadiException {
77                 this((AAFCon<CLIENT>)mustBeAAFCon,turnOnWarning,other);
78         }
79
80         // Note: Needed for Creation of this Object with Generics
81         @SuppressWarnings("unchecked")
82         public AAFTaf(Connector mustBeAAFCon, boolean turnOnWarning) throws CadiException {
83                 this((AAFCon<CLIENT>)mustBeAAFCon,turnOnWarning);
84         }
85
86
87         public TafResp validate(final LifeForm reading, final HttpServletRequest req, final HttpServletResponse resp) {
88                 //TODO Do we allow just anybody to validate?
89
90                 // Note: Either Carbon or Silicon based LifeForms ok
91                 String authz = req.getHeader("Authorization");
92                 if(authz != null && authz.startsWith("Basic ")) {
93                         if(warn&&!req.isSecure())aaf.access.log(Level.WARN,"WARNING! BasicAuth has been used over an insecure channel");
94                         try {
95                                 final CachedBasicPrincipal bp;
96                                 if(req.getUserPrincipal() instanceof CachedBasicPrincipal) {
97                                         bp = (CachedBasicPrincipal)req.getUserPrincipal();
98                                 } else {
99                                         bp = new CachedBasicPrincipal(this,authz,aaf.getRealm(),aaf.userExpires);
100                                 }
101                                 // First try Cache
102                                 final User<AAFPermission> usr = getUser(bp);
103                                 if(usr != null && usr.principal != null) {
104                                         if(usr.principal instanceof GetCred) {
105                                                 if(Hash.isEqual(bp.getCred(),((GetCred)usr.principal).getCred())) {
106                                                         return new BasicHttpTafResp(aaf.access,bp,bp.getName()+" authenticated by cached AAF password",RESP.IS_AUTHENTICATED,resp,aaf.getRealm(),false);
107                                                 }
108                                         }
109                                 }
110                                 
111                                 Miss miss = missed(bp.getName(), bp.getCred());
112                                 if(miss!=null && !miss.mayContinue()) {
113                                         return new BasicHttpTafResp(aaf.access,null,buildMsg(bp,req,
114                                                         "User/Pass Retry limit exceeded"), 
115                                                         RESP.TRY_AUTHENTICATING,resp,aaf.getRealm(),true);
116                                 }
117                                 
118                                 return aaf.bestForUser(
119                                         new GetSetter() {
120                                                 @Override
121                                                 public <CL> SecuritySetter<CL> get(AAFCon<CL> con) throws CadiException {
122                                                         return con.basicAuthSS(bp);
123                                                 }
124                                         },new Retryable<BasicHttpTafResp>() {
125                                                 @Override
126                                                 public BasicHttpTafResp code(Rcli<?> client) throws CadiException, ConnectException, APIException {
127                                                         Future<String> fp = client.read("/authn/basicAuth", "text/plain");
128                                                         if(fp.get(aaf.timeout)) {
129                                                                 if(usr!=null) {
130                                                                         usr.principal = bp;
131                                                                 } else {
132                                                                         addUser(new User<AAFPermission>(bp,aaf.userExpires));
133                                                                 }
134                                                                 return new BasicHttpTafResp(aaf.access,bp,bp.getName()+" authenticated by AAF password",RESP.IS_AUTHENTICATED,resp,aaf.getRealm(),false);
135                                                         } else {
136                                                                 // Note: AddMiss checks for miss==null, and is part of logic
137                                                                 boolean rv= addMiss(bp.getName(),bp.getCred());
138                                                                 if(rv) {
139                                                                         return new BasicHttpTafResp(aaf.access,null,buildMsg(bp,req,
140                                                                                         "user/pass combo invalid via AAF from " + req.getRemoteAddr()), 
141                                                                                         RESP.TRY_AUTHENTICATING,resp,aaf.getRealm(),true);
142                                                                 } else {
143                                                                         return new BasicHttpTafResp(aaf.access,null,buildMsg(bp,req,
144                                                                                         "user/pass combo invalid via AAF from " + req.getRemoteAddr() + " - Retry limit exceeded"), 
145                                                                                         RESP.FAIL,resp,aaf.getRealm(),true);
146                                                                 }
147                                                         }
148                                                 }
149                                         }
150                                 );
151                         } catch (IOException e) {
152                                 String msg = buildMsg(null,req,"Invalid Auth Token");
153                                 aaf.access.log(Level.WARN,msg,'(', e.getMessage(), ')');
154                                 return new BasicHttpTafResp(aaf.access,null,msg, RESP.TRY_AUTHENTICATING, resp, aaf.getRealm(),true);
155                         } catch (Exception e) {
156                                 String msg = buildMsg(null,req,"Authenticating Service unavailable");
157                                 try {
158                                         aaf.invalidate();
159                                 } catch (CadiException e1) {
160                                         aaf.access.log(e1, "Error Invalidating Client");
161                                 }
162                                 aaf.access.log(Level.WARN,msg,'(', e.getMessage(), ')');
163                                 return new BasicHttpTafResp(aaf.access,null,msg, RESP.FAIL, resp, aaf.getRealm(),false);
164                         }
165                 }
166                 return new BasicHttpTafResp(aaf.access,null,"Requesting HTTP Basic Authorization",RESP.TRY_AUTHENTICATING,resp,aaf.getRealm(),false);
167         }
168         
169         public String buildMsg(Principal pr, HttpServletRequest req, Object ... msg) {
170                 StringBuilder sb = new StringBuilder();
171                 for(Object s : msg) {
172                         sb.append(s.toString());
173                 }
174                 if(pr!=null) {
175                         sb.append(" for ");
176                         sb.append(pr.getName());
177                 }
178                 sb.append(" from ");
179                 sb.append(req.getRemoteAddr());
180                 sb.append(':');
181                 sb.append(req.getRemotePort());
182                 return sb.toString();
183         }
184
185
186         
187         public Resp revalidate(CachedPrincipal prin, Object state) {
188                 //  !!!! TEST THIS.. Things may not be revalidated, if not BasicPrincipal
189                 if(prin instanceof BasicPrincipal) {
190                         Future<String> fp;
191                         try {
192                                 Rcli<CLIENT> userAAF = aaf.client(Config.AAF_DEFAULT_VERSION).forUser(aaf.transferSS((BasicPrincipal)prin));
193                                 fp = userAAF.read("/authn/basicAuth", "text/plain");
194                                 return fp.get(aaf.timeout)?Resp.REVALIDATED:Resp.UNVALIDATED;
195                         } catch (Exception e) {
196                                 aaf.access.log(e, "Cannot Revalidate",prin.getName());
197                                 return Resp.INACCESSIBLE;
198                         }
199                 }
200                 return Resp.NOT_MINE;
201         }
202
203 }