Remove Tabs, per Jococo
[aaf/authz.git] / cadi / core / src / main / java / org / onap / aaf / cadi / filter / MapBathConverter.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.filter;
23
24 import java.io.IOException;
25 import java.text.ParseException;
26 import java.text.SimpleDateFormat;
27 import java.util.Date;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.TreeMap;
31
32 import javax.xml.ws.Holder;
33
34 import org.onap.aaf.cadi.Access;
35 import org.onap.aaf.cadi.Access.Level;
36 import org.onap.aaf.cadi.CadiException;
37 import org.onap.aaf.cadi.Symm;
38 import org.onap.aaf.cadi.util.CSV;
39 import org.onap.aaf.cadi.util.CSV.Visitor;
40
41 /**
42  * This Filter is designed to help MIGRATE users from systems that don't match the FQI style.  
43  *  
44  * Style 1, where just the ID is translated, i.e. OLD => new@something.onap.org, that is acceptable
45  * longer term, because it does not store Creds locally.  The passwords are in appropriate systems, but
46  * it's still painful operationally, though it does ease migration.
47  *
48  * Style 3, however, which is Direct match of Authorization Header to replacement, is only there
49  * because some passwords are simply not acceptable for AAF, (too easy, for instance), and it is
50  * not feasible to break Organization Password rules for a Migration.  Therefore, this method 
51  * should not considered something that is in any way a permanent
52  * 
53
54  * 
55  * It goes without saying that any file with the password conversion should be protected by "400", etc.
56  * 
57  * @author Instrumental (Jonathan)
58  *
59  */
60 public class MapBathConverter {
61     private static final String BASIC = "Basic ";
62     private final Map<String,String> map;
63
64     /**
65      * Create with colon separated name value pairs
66      *  Enter the entire "Basic dXNlcjpwYXNz" "Authorization" header, where "dXNlcjpwYXNz" is 
67      *  base64 encoded, which can be created with "cadi" tool (in jar)
68      *  
69      *  The replacement should also be an exact replacement of what you want.  Recognize that 
70      *  this should be TEMPORARY as you are storing credentials outside the users control. 
71      *  
72      * @param value
73      * @throws IOException 
74      * @throws CadiException 
75      */
76     public MapBathConverter(final Access access, final CSV csv) throws IOException, CadiException {
77         map = new TreeMap<>();
78         final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
79         final Date now = new Date();
80         csv.visit(new Visitor() {
81             @Override
82             public void visit(List<String> row) throws CadiException {
83                 if(row.size()<3) {
84                     throw new CadiException("CSV file " + csv + " must have at least 2 Basic Auth columns and an Expiration Date(YYYY-MM-DD) in each row");
85                 }
86                 try {
87                     Date date = sdf.parse(row.get(2));
88                     String oldID = row.get(0);
89                     String newID = row.get(1);
90                     if(date.after(now)) {
91                         if(!oldID.startsWith(BASIC) && newID.startsWith(BASIC)) {
92                             throw new CadiException("CSV file " + csv + ": Uncredentialed ID " + idFromBasic(oldID,null) +
93                                                     " may not transfer to credentialed ID " + idFromBasic(newID,null));
94                         } else {
95                             map.put(oldID,newID);
96                             access.printf(Level.INIT, "ID Conversion from %s to %s enabled",
97                                     idFromBasic(oldID,null),
98                                     idFromBasic(newID,null));
99                         }
100                     } else {
101                         access.printf(Level.INIT, "ID Conversion from %s to %s has expired.",
102                                 idFromBasic(oldID,null),
103                                 idFromBasic(newID,null));
104                     }
105                 } catch (ParseException e) {
106                     throw new CadiException("Cannot Parse Date: " + row.get(2));
107                 } catch (IOException e) {
108                     throw new CadiException(e);
109                 }
110             }
111         });
112     }
113     
114     private static String idFromBasic(String bath, Holder<String> hpass) throws IOException, CadiException {
115         if(bath.startsWith(BASIC)) {
116             String cred = Symm.base64noSplit.decode(bath.substring(6));
117             int colon = cred.indexOf(':');
118             if(colon<0) {
119                 throw new CadiException("Invalid Authentication Credential for " + cred);
120             }
121             if(hpass!=null) {
122                 hpass.value = cred.substring(colon+1);
123             }
124             return cred.substring(0, colon);
125         } else {
126             return bath;
127         }
128     }
129
130     /**
131      * use to instantiate entries 
132      * 
133      * @return
134      */
135     public Map<String,String> map() {
136         return map;
137     }
138
139     public String convert(Access access, final String bath) {
140         String rv = map.get(bath);
141
142         String cred;
143         String tcred=null;
144         Holder<String> hpass=null;
145         try {
146             if(bath.startsWith(BASIC)) {
147                 cred = idFromBasic(bath,(hpass=new Holder<String>()));
148                 if(rv==null) {
149                     rv = map.get(cred);
150                 }
151             } else {
152                 cred = bath;
153             }
154
155             if(rv==null) {
156                 // Nothing here, just return original
157                 rv = bath;
158             } else {
159                 if(rv.startsWith(BASIC)) {
160                     tcred = idFromBasic(rv,null);
161                 } else {
162                     if(hpass!=null) {
163                         tcred = rv;
164                         rv = BASIC + Symm.base64noSplit.encode(rv+':'+hpass.value);
165                     }
166                 }
167                 if(tcred != null) {
168                     access.printf(Level.AUDIT, "ID %s converted to %s",cred,tcred);
169                 }
170             }
171         } catch (IOException | CadiException e) {
172             access.log(e,"Invalid Authorization");
173         }
174         return rv==null?bath:rv;
175     }
176 }