Collection syntax change because of Sonar
[aaf/authz.git] / cadi / core / src / main / java / org / onap / aaf / cadi / taf / HttpEpiTaf.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.taf;
23
24 import java.net.URI;
25 import java.security.Principal;
26 import java.util.ArrayList;
27 import java.util.List;
28
29 import javax.servlet.http.HttpServletRequest;
30 import javax.servlet.http.HttpServletResponse;
31
32 import org.onap.aaf.cadi.Access;
33 import org.onap.aaf.cadi.Access.Level;
34 import org.onap.aaf.cadi.CachedPrincipal;
35 import org.onap.aaf.cadi.CachedPrincipal.Resp;
36 import org.onap.aaf.cadi.CadiException;
37 import org.onap.aaf.cadi.Locator;
38 import org.onap.aaf.cadi.Taf.LifeForm;
39 import org.onap.aaf.cadi.TrustChecker;
40
41 /**
42  * HttpEpiTaf
43  *
44  * An extension of the basic "EpiTAF" concept, check known HTTP Related TAFs for valid credentials
45  *
46  * @author Jonathan
47  *
48  */
49 public class HttpEpiTaf implements HttpTaf {
50         private HttpTaf[] tafs;
51         private Access access;
52         private Locator<URI> locator;
53         private TrustChecker trustChecker;
54
55         /**
56          * HttpEpiTaf constructor
57          *
58          * Construct the HttpEpiTaf from variable Http specific TAF parameters
59
60          * @param tafs
61          * @throws CadiException
62          */
63         public HttpEpiTaf(Access access, Locator<URI> locator, TrustChecker tc, HttpTaf ... tafs) throws CadiException{
64                 this.tafs = tafs;
65                 this.access = access;
66                 this.locator = locator;
67                 this.trustChecker = tc;
68                 // Establish what Header Property to look for UserChain/Trust Props
69
70                 if (tafs.length == 0) {
71                         throw new CadiException("Need at least one HttpTaf implementation in constructor");
72                 }
73         }
74
75         /**
76          * validate
77          *
78          * Respond with the first Http specific TAF to authenticate user based on variable info
79          * and "LifeForm" (is it a human behind a browser, or a server utilizing HTTP Protocol).
80          *
81          * If there is no HttpTAF that can authenticate, respond with the first TAF that suggests it can
82          * establish an Authentication conversation (TRY_AUTHENTICATING) (Examples include a redirect to CSP
83          * Servers for CSP Cookie, or BasicAuth 401 response, suggesting User/Password for given Realm
84          * submission
85          *
86          * If no TAF declares either, respond with NullTafResp (which denies all questions)
87          */
88         public TafResp validate(LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {
89                 // Given a LifeForm Neutral, for HTTP, we need to discover true Life-Form Readings
90                 if (reading == LifeForm.LFN) {
91                         reading = tricorderScan(req);
92                 }
93                 TafResp tresp = null;
94                 TafResp firstTry = null;
95                 List<Redirectable> redirectables = null;
96                 List<TafResp> log;
97                 if(access.willLog(Level.DEBUG)) {
98                         log = new ArrayList<>();
99                 } else {
100                         log = null;
101                 }
102                 try {
103                         for (HttpTaf taf : tafs) {
104                                 tresp = taf.validate(reading, req, resp);
105                                 addToLog(log, tresp);
106                                 switch(tresp.isAuthenticated()) {
107                                         case TRY_ANOTHER_TAF:
108                                                 break; // and loop
109                                         case TRY_AUTHENTICATING:
110                                                 if (tresp instanceof Redirectable) {
111                                                         if (redirectables == null) {
112                                                                 redirectables = new ArrayList<>();
113                                                         }
114                                                         redirectables.add((Redirectable)tresp);
115                                                 } else if (firstTry == null) {
116                                                         firstTry = tresp;
117                                                 }
118                                                 break;
119                                         case IS_AUTHENTICATED:
120                                                 tresp = trustChecker.mayTrust(tresp, req);
121                                                 return tresp;
122                                         default:
123                                                 return tresp;
124                                 }
125                         }
126                 } finally {
127                         printLog(log);
128                 }
129
130                 // If No TAFs configured, at this point.  It is safer at this point to be "not validated",
131                 // rather than "let it go"
132                 // Note: if exists, there will always be more than 0 entries, according to above code
133                 if (redirectables == null) {
134                         return (firstTry != null) ? firstTry : NullTafResp.singleton();
135                 }
136
137                 // If there is one Tryable entry then return it
138                 if (redirectables.size() > 1) {
139                         return LoginPageTafResp.create(access, locator, resp, redirectables);
140                 } else {
141                         return redirectables.get(0);
142                 }
143         }
144
145         public boolean revalidate(Principal prin) throws Exception {
146                 return false;
147         }
148
149         /*
150          * Since this is internal, we use a little Star Trek humor to indicate looking in the HTTP Request to see if we can determine what kind
151          * of "LifeForm" reading we can determine, i.e. is there a Human (CarbonBasedLifeForm) behind a browser, or is it mechanical
152          * id (SiliconBasedLifeForm)?  This makes a difference in some Authentication, i.e CSP, which doesn't work well for SBLFs
153          */
154         private LifeForm tricorderScan(HttpServletRequest req) {
155                 // For simplicity's sake, we'll say Humans use FQDNs, not IPs.
156
157                 // Current guess that only Browsers bother to set "Agent" codes that identify the kind of browser they are.
158                 // If mechanical frameworks are found that populate this, then more advanced analysis may be required
159                 // Jonathan 1/22/2013
160                 String agent = req.getHeader("User-Agent");
161                 if (agent != null && agent.startsWith("Mozilla")) { // covers I.E./Firefox/Safari/probably any other "advanced" Browser see http://en.wikipedia.org/wiki/User_agent
162                         return LifeForm.CBLF;
163                 }
164                 return LifeForm.SBLF;                                                   // notably skips "curl","wget", (which is desired behavior.  We don't want to try CSP, etc on these)
165         }
166
167         public Resp revalidate(CachedPrincipal prin, Object state) {
168                 Resp resp;
169                 for (HttpTaf taf : tafs) {
170                         resp = taf.revalidate(prin, state);
171                         if (resp != Resp.NOT_MINE) {
172                                 return resp;
173                         }
174 //                      switch(resp) {
175 //                              case NOT_MINE:
176 //                                      break;
177 //                              default:
178 //                                      return resp;
179 //                      }
180                 }
181                 return Resp.NOT_MINE;
182         }
183         
184         private void addToLog(List<TafResp> log, TafResp tresp) {
185                 if (log == null) {
186                         return;
187                 }
188                 log.add(tresp);
189         }
190         
191         private void printLog(List<TafResp> log) {
192                 if (log == null) {
193                         return;
194                 }
195                 for (TafResp tresp : log) {
196                         access.log(Level.DEBUG, tresp.desc());
197                 }
198         }
199
200         /**
201          * List HttpTafs with their "toString" representations... primarily useful for Debugging in an IDE
202          * like Eclipse.
203          */
204         public String toString() {
205                 StringBuilder sb = new StringBuilder();
206                 for (HttpTaf ht : tafs) {
207                         sb.append(ht.toString());
208                         sb.append(". ");
209                 }
210                 return sb.toString();
211         }
212 }