1 /*******************************************************************************
\r
2 * ============LICENSE_START====================================================
\r
4 * * ===========================================================================
\r
5 * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
\r
6 * * ===========================================================================
\r
7 * * Licensed under the Apache License, Version 2.0 (the "License");
\r
8 * * you may not use this file except in compliance with the License.
\r
9 * * You may obtain a copy of the License at
\r
11 * * http://www.apache.org/licenses/LICENSE-2.0
\r
13 * * Unless required by applicable law or agreed to in writing, software
\r
14 * * distributed under the License is distributed on an "AS IS" BASIS,
\r
15 * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
16 * * See the License for the specific language governing permissions and
\r
17 * * limitations under the License.
\r
18 * * ============LICENSE_END====================================================
\r
20 * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
\r
22 ******************************************************************************/
\r
23 package com.att.cadi.taf.basic;
\r
25 import java.io.IOException;
\r
26 import java.security.Principal;
\r
28 import javax.servlet.http.HttpServletRequest;
\r
29 import javax.servlet.http.HttpServletResponse;
\r
31 import com.att.cadi.Access;
\r
32 import com.att.cadi.Access.Level;
\r
33 import com.att.cadi.BasicCred;
\r
34 import com.att.cadi.CachedPrincipal;
\r
35 import com.att.cadi.CachedPrincipal.Resp;
\r
36 import com.att.cadi.CredVal;
\r
37 import com.att.cadi.CredVal.Type;
\r
38 import com.att.cadi.Taf;
\r
39 import com.att.cadi.principal.BasicPrincipal;
\r
40 import com.att.cadi.principal.CachedBasicPrincipal;
\r
41 import com.att.cadi.taf.HttpTaf;
\r
42 import com.att.cadi.taf.TafResp;
\r
43 import com.att.cadi.taf.TafResp.RESP;
\r
44 import com.att.cadi.taf.dos.DenialOfServiceTaf;
\r
49 * This TAF implements the "Basic Auth" protocol.
\r
51 * WARNING! It is true for any implementation of "Basic Auth" that the password is passed unencrypted.
\r
52 * This is because the expectation, when designed years ago, was that it would only be used in
\r
53 * conjunction with SSL (https). It is common, however, for users to ignore this on the assumption that
\r
54 * their internal network is secure, or just ignorance. Therefore, a WARNING will be printed
\r
55 * when the HTTP Channel is not encrypted (unless explicitly turned off).
\r
59 public class BasicHttpTaf implements HttpTaf {
\r
60 private Access access;
\r
61 private String realm;
\r
62 private CredVal rbac;
\r
63 private boolean warn;
\r
64 private long timeToLive;
\r
66 public BasicHttpTaf(Access access, CredVal rbac, String realm, long timeToLive, boolean turnOnWarning) {
\r
67 this.access = access;
\r
70 this.warn = turnOnWarning;
\r
71 this.timeToLive = timeToLive;
\r
75 * Note: BasicHttp works for either Carbon Based (Humans) or Silicon Based (machine) Lifeforms.
\r
78 public TafResp validate(Taf.LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {
\r
79 // See if Request implements BasicCred (aka CadiWrap or other), and if User/Pass has already been set separately
\r
80 if(req instanceof BasicCred) {
\r
81 BasicCred bc = (BasicCred)req;
\r
82 if(bc.getUser()!=null) { // CadiWrap, if set, makes sure User & Password are both valid, or both null
\r
83 if(DenialOfServiceTaf.isDeniedID(bc.getUser())!=null) {
\r
84 return DenialOfServiceTaf.respDenyID(access,bc.getUser());
\r
86 CachedBasicPrincipal bp = new CachedBasicPrincipal(this,bc,realm,timeToLive);
\r
87 // ONLY FOR Last Ditch DEBUGGING...
\r
88 // access.log(Level.WARN,bp.getName() + ":" + new String(bp.getCred()));
\r
89 if(rbac.validate(bp.getName(),Type.PASSWORD,bp.getCred())) {
\r
90 return new BasicHttpTafResp(access,bp,bp.getName()+" authenticated by password",RESP.IS_AUTHENTICATED,resp,realm,false);
\r
92 //TODO may need timed retries in a given time period
\r
93 return new BasicHttpTafResp(access,null,buildMsg(bp,req,"User/Pass combo invalid for ",bc.getUser()),
\r
94 RESP.TRY_AUTHENTICATING,resp,realm,true);
\r
98 // Get User/Password from Authorization Header value
\r
99 String authz = req.getHeader("Authorization");
\r
100 if(authz != null && authz.startsWith("Basic ")) {
\r
101 if(warn&&!req.isSecure()) {
\r
102 access.log(Level.WARN,"WARNING! BasicAuth has been used over an insecure channel");
\r
105 CachedBasicPrincipal ba = new CachedBasicPrincipal(this,authz,realm,timeToLive);
\r
106 if(DenialOfServiceTaf.isDeniedID(ba.getName())!=null) {
\r
107 return DenialOfServiceTaf.respDenyID(access,ba.getName());
\r
110 // ONLY FOR Last Ditch DEBUGGING...
\r
111 // access.log(Level.WARN,ba.getName() + ":" + new String(ba.getCred()));
\r
112 if(rbac.validate(ba.getName(), Type.PASSWORD, ba.getCred())) {
\r
113 return new BasicHttpTafResp(access,ba, ba.getName()+" authenticated by BasicAuth password",RESP.IS_AUTHENTICATED,resp,realm,false);
\r
115 //TODO may need timed retries in a given time period
\r
116 return new BasicHttpTafResp(access,null,buildMsg(ba,req,"User/Pass combo invalid"),
\r
117 RESP.TRY_AUTHENTICATING,resp,realm,true);
\r
119 } catch (IOException e) {
\r
120 String msg = buildMsg(null,req,"Failed HTTP Basic Authorization (", e.getMessage(), ')');
\r
121 access.log(Level.INFO,msg);
\r
122 return new BasicHttpTafResp(access,null,msg, RESP.TRY_AUTHENTICATING, resp, realm,true);
\r
125 return new BasicHttpTafResp(access,null,"Requesting HTTP Basic Authorization",RESP.TRY_AUTHENTICATING,resp,realm,false);
\r
128 protected String buildMsg(Principal pr, HttpServletRequest req, Object ... msg) {
\r
129 StringBuilder sb = new StringBuilder();
\r
130 for(Object s : msg) {
\r
131 sb.append(s.toString());
\r
134 sb.append(" for ");
\r
135 sb.append(pr.getName());
\r
137 sb.append(" from ");
\r
138 sb.append(req.getRemoteAddr());
\r
140 sb.append(req.getRemotePort());
\r
141 return sb.toString();
\r
145 public Resp revalidate(CachedPrincipal prin) {
\r
146 if(prin instanceof BasicPrincipal) {
\r
147 BasicPrincipal ba = (BasicPrincipal)prin;
\r
148 if(DenialOfServiceTaf.isDeniedID(ba.getName())!=null) {
\r
149 return Resp.UNVALIDATED;
\r
151 return rbac.validate(ba.getName(), Type.PASSWORD, ba.getCred())?Resp.REVALIDATED:Resp.UNVALIDATED;
\r
153 return Resp.NOT_MINE;
\r
156 public String toString() {
\r
157 return "Basic Auth enabled on realm: " + realm;
\r