2 * ============LICENSE_START====================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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====================================================
22 package org.onap.aaf.cadi.taf;
25 import java.security.Principal;
26 import java.util.ArrayList;
27 import java.util.List;
29 import javax.servlet.http.HttpServletRequest;
30 import javax.servlet.http.HttpServletResponse;
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;
44 * An extension of the basic "EpiTAF" concept, check known HTTP Related TAFs for valid credentials
49 public class HttpEpiTaf implements HttpTaf {
50 private HttpTaf[] tafs;
51 private Access access;
52 private Locator<URI> locator;
53 private TrustChecker trustChecker;
56 * HttpEpiTaf constructor
58 * Construct the HttpEpiTaf from variable Http specific TAF parameters
61 * @throws CadiException
63 public HttpEpiTaf(Access access, Locator<URI> locator, TrustChecker tc, HttpTaf ... tafs) throws CadiException{
66 this.locator = locator;
67 this.trustChecker = tc;
68 // Establish what Header Property to look for UserChain/Trust Props
69 // trustChainProp = access.getProperty(Config.CADI_TRUST_PROP, Config.CADI_TRUST_PROP_DEFAULT);
71 if(tafs.length==0) throw new CadiException("Need at least one HttpTaf implementation in constructor");
77 * Respond with the first Http specific TAF to authenticate user based on variable info
78 * and "LifeForm" (is it a human behind a browser, or a server utilizing HTTP Protocol).
80 * If there is no HttpTAF that can authenticate, respond with the first TAF that suggests it can
81 * establish an Authentication conversation (TRY_AUTHENTICATING) (Examples include a redirect to CSP
82 * Servers for CSP Cookie, or BasicAuth 401 response, suggesting User/Password for given Realm
85 * If no TAF declares either, respond with NullTafResp (which denies all questions)
87 public TafResp validate(LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {
88 // Given a LifeForm Neutral, for HTTP, we need to discover true Life-Form Readings
89 if(reading==LifeForm.LFN) {
90 reading = tricorderScan(req);
92 TafResp tresp=null, firstTry = null;
93 List<Redirectable> redirectables = null;
94 List<TafResp> trlog = access.willLog(Level.DEBUG)?new ArrayList<TafResp>():null;
96 for(HttpTaf taf : tafs) {
97 tresp = taf.validate(reading, req, resp);
101 switch(tresp.isAuthenticated()) {
102 case TRY_ANOTHER_TAF:
104 case TRY_AUTHENTICATING:
105 if(tresp instanceof Redirectable) {
106 if(redirectables==null) {
107 redirectables = new ArrayList<Redirectable>();
109 redirectables.add((Redirectable)tresp);
110 } else if(firstTry==null) {
114 case IS_AUTHENTICATED:
115 tresp = trustChecker.mayTrust(tresp, req);
123 for( TafResp tr : trlog) {
124 access.log(Level.DEBUG, tr.desc());
129 // If No TAFs configured, at this point. It is safer at this point to be "not validated",
130 // rather than "let it go"
131 // Note: if exists, there will always be more than 0 entries, according to above code
132 if(redirectables==null) {
133 return firstTry!=null?firstTry:NullTafResp.singleton();
136 // If there is one Tryable entry then return it
137 if(redirectables.size()>1) {
138 return LoginPageTafResp.create(access,locator,resp,redirectables);
140 return redirectables.get(0);
144 public boolean revalidate(Principal prin) throws Exception {
149 * 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
150 * of "LifeForm" reading we can determine, i.e. is there a Human (CarbonBasedLifeForm) behind a browser, or is it mechanical
151 * id (SiliconBasedLifeForm)? This makes a difference in some Authentication, i.e CSP, which doesn't work well for SBLFs
153 private LifeForm tricorderScan(HttpServletRequest req) {
154 // For simplicity's sake, we'll say Humans use FQDNs, not IPs.
156 // Current guess that only Browsers bother to set "Agent" codes that identify the kind of browser they are.
157 // If mechanical frameworks are found that populate this, then more advanced analysis may be required
158 // Jonathan 1/22/2013
159 String agent = req.getHeader("User-Agent");
160 if(agent!=null && agent.startsWith("Mozilla")) { // covers I.E./Firefox/Safari/probably any other "advanced" Browser see http://en.wikipedia.org/wiki/User_agent
161 return LifeForm.CBLF;
163 return LifeForm.SBLF; // notably skips "curl","wget", (which is desired behavior. We don't want to try CSP, etc on these)
166 public Resp revalidate(CachedPrincipal prin, Object state) {
168 for(HttpTaf taf : tafs) {
169 resp = taf.revalidate(prin,state);
177 return Resp.NOT_MINE;
181 * List HttpTafs with their "toString" representations... primarily useful for Debugging in an IDE
184 public String toString() {
185 StringBuilder sb = new StringBuilder();
186 for(HttpTaf ht : tafs) {
187 sb.append(ht.toString());
190 return sb.toString();