Choose better Concurrency Object
[aaf/cadi.git] / shiro / src / main / java / org / onap / aaf / cadi / shiro / AAFRealm.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 package org.onap.aaf.cadi.shiro;
22
23 import java.io.IOException;
24 import java.security.Principal;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Map.Entry;
31 import java.util.Set;
32 import java.util.TreeMap;
33
34 import org.apache.shiro.authc.AuthenticationException;
35 import org.apache.shiro.authc.AuthenticationInfo;
36 import org.apache.shiro.authc.AuthenticationToken;
37 import org.apache.shiro.authc.UsernamePasswordToken;
38 import org.apache.shiro.realm.AuthorizingRealm;
39 import org.apache.shiro.subject.PrincipalCollection;
40 import org.onap.aaf.cadi.Access.Level;
41 import org.onap.aaf.cadi.CadiException;
42 import org.onap.aaf.cadi.LocatorException;
43 import org.onap.aaf.cadi.Permission;
44 import org.onap.aaf.cadi.PropAccess;
45 import org.onap.aaf.cadi.Symm;
46 import org.onap.aaf.cadi.aaf.v2_0.AAFAuthn;
47 import org.onap.aaf.cadi.aaf.v2_0.AAFCon;
48 import org.onap.aaf.cadi.aaf.v2_0.AAFLurPerm;
49 import org.onap.aaf.cadi.config.Config;
50 import org.onap.aaf.cadi.filter.MapBathConverter;
51 import org.onap.aaf.cadi.util.CSV;
52 import org.onap.aaf.misc.env.APIException;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 public class AAFRealm extends AuthorizingRealm {
57         public static final String AAF_REALM = "AAFRealm";
58         private static final Logger logger =  LoggerFactory.getLogger(AAFRealm.class);
59         private static Singleton singleton = Singleton.singleton();
60         
61         private static class Singleton {
62                 private AAFCon<?> acon;
63                 private AAFAuthn<?> authn;
64                 private Set<Class<? extends AuthenticationToken>> supports;
65                 private AAFLurPerm authz;
66                 private MapBathConverter mbc;
67                 private Map<String,String> idMap;
68                 private Singleton() {
69                         mbc = null;
70                         idMap = null;
71                         String cadi_prop_files = access.getProperty(Config.CADI_PROP_FILES);
72                         if(cadi_prop_files==null) {
73                                 String msg = Config.CADI_PROP_FILES + " in VM Args is required to initialize AAFRealm.";
74                                 access.log(Level.INFO,msg);
75                                 throw new RuntimeException(msg);
76                         } else {
77                                 try {
78                                         acon = AAFCon.newInstance(access);
79                                         authn = acon.newAuthn();
80                                         authz = acon.newLur(authn);
81                                         
82                                         final String csv = access.getProperty(Config.CADI_BATH_CONVERT);
83                                         if(csv!=null) {
84                                                 try {
85                                                         mbc = new MapBathConverter(access, new CSV(csv));
86                                                         access.log(Level.INFO, "MapBathConversion enabled with file ",csv);
87                                                         idMap = Collections.synchronizedMap(new TreeMap<String,String>());
88                                                         // Load 
89                                                         for(Entry<String, String> es : mbc.map().entrySet()) {
90                                                                 String oldID = es.getKey();
91                                                                 if(oldID.startsWith("Basic ")) {
92                                                                         oldID = Symm.base64noSplit.decode(oldID.substring(6));
93                                                                         int idx = oldID.indexOf(':');
94                                                                         if(idx>=0) {
95                                                                                 oldID = oldID.substring(0, idx);
96                                                                         }
97                                                                 }
98                                                                 String newID = es.getValue();
99                                                                 if(newID.startsWith("Basic ")) {
100                                                                         newID = Symm.base64noSplit.decode(newID.substring(6));
101                                                                         int idx = newID.indexOf(':');
102                                                                         if(idx>=0) {
103                                                                                 newID = newID.substring(0, idx);
104                                                                         }
105                                                                 }
106                                                                 idMap.put(oldID,newID);
107                                                                 
108                                                         }
109                                                 } catch (IOException e) {
110                                                         access.log(e);
111                                                 }
112                                         }
113                                 } catch (APIException | CadiException | LocatorException e) {
114                                         String msg = "Cannot initiate AAFRealm";
115                                         access.log(Level.ERROR,e,msg);
116                                         throw new RuntimeException(msg,e);
117                                 }
118                         }
119                         supports = Collections.synchronizedSet(new HashSet<>());
120                         supports.add(UsernamePasswordToken.class);
121                 }
122                 
123                 public static synchronized Singleton singleton() {
124                         if(singleton==null) {
125                                 singleton = new Singleton();
126                         }
127                         return singleton;
128                 }
129
130                 // pick up cadi_prop_files from VM_Args
131                 private final PropAccess access = new PropAccess() {
132                         @Override
133                         public void log(Exception e, Object... elements) {
134                                 logger.error(buildMsg(Level.ERROR, elements).toString(),e);
135                         }
136                 
137                         @Override
138                         public void log(Level level, Object... elements) {
139                                 if(willLog(level)) {
140                                         String str = buildMsg(level, elements).toString();
141                                         switch(level) {
142                                                 case WARN:
143                                                 case AUDIT:
144                                                         logger.warn(str);
145                                                         break;
146                                                 case DEBUG:
147                                                         logger.debug(str);
148                                                         break;
149                                                 case ERROR:
150                                                         logger.error(str);
151                                                         break;
152                                                 case INFO:
153                                                 case INIT:
154                                                         logger.info(str);
155                                                         break;
156                                                 case NONE:
157                                                         break;
158                                                 case TRACE:
159                                                         logger.trace(str);
160                                                         break;
161                                         }
162                                 }
163                         }
164                 
165                         @Override
166                         public void printf(Level level, String fmt, Object... elements) {
167                                 if(willLog(level)) {
168                                         String str = String.format(fmt, elements);
169                                         switch(level) {
170                                                 case WARN:
171                                                 case AUDIT:
172                                                         logger.warn(str);
173                                                         break;
174                                                 case DEBUG:
175                                                         logger.debug(str);
176                                                         break;
177                                                 case ERROR:
178                                                         logger.error(str);
179                                                         break;
180                                                 case INFO:
181                                                 case INIT:
182                                                         logger.info(str);
183                                                         break;
184                                                 case NONE:
185                                                         break;
186                                                 case TRACE:
187                                                         logger.trace(str);
188                                                         break;
189                                         }
190                                 }
191                         }
192                 
193                         @Override
194                         public boolean willLog(Level level) {
195                                 if(super.willLog(level)) {
196                                         switch(level) {
197                                                 case WARN:
198                                                 case AUDIT:
199                                                         return logger.isWarnEnabled();
200                                                 case DEBUG:
201                                                         return logger.isDebugEnabled();
202                                                 case ERROR:
203                                                         return logger.isErrorEnabled();
204                                                 case INFO:
205                                                 case INIT:
206                                                         return logger.isInfoEnabled();
207                                                 case NONE:
208                                                         return false;
209                                                 case TRACE:
210                                                         return logger.isTraceEnabled();
211                                         }
212                                 }
213                                 return false;
214                         }
215                 };
216         }               
217         
218         /**
219          * 
220          * There appears to be no configuration objects or references available for CADI to start with.
221          *  
222          */
223
224         @Override
225         protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
226                 final UsernamePasswordToken upt = (UsernamePasswordToken)token;
227                 final String user = upt.getUsername();
228                 String authUser = user; 
229                 final String password=new String(upt.getPassword());
230                 String authPassword = password;
231                 if(singleton.mbc!=null) {
232                         try {
233                                 final String oldBath = "Basic " + Symm.base64noSplit.encode(user+':'+password);
234                                 String bath = singleton.mbc.convert(singleton.access, oldBath);
235                                 if(bath!=oldBath) {
236                                         bath = Symm.base64noSplit.decode(bath.substring(6));
237                                         int colon = bath.indexOf(':');
238                                         if(colon>=0) {
239                                                 authUser = bath.substring(0, colon);
240                                                 authPassword = bath.substring(colon+1); 
241                                         }
242                                 }
243                         } catch (IOException e) {
244                                 singleton.access.log(e);
245                         } 
246                 }
247                 String err;
248                 try {
249                         err = singleton.authn.validate(authUser,authPassword);
250                         if(err != null) {
251                                 singleton.access.log(Level.INFO, err);
252                                 throw new AuthenticationException(err);
253                         }
254
255                 } catch (IOException e) {
256                         singleton.access.log(e,"Credential cannot be validated");
257                 }
258                 
259             return new AAFAuthenticationInfo(
260                         singleton.access,
261                         user,
262                         password
263             );
264         }
265
266         @Override
267         protected void assertCredentialsMatch(AuthenticationToken atoken, AuthenticationInfo ai)throws AuthenticationException {
268                 
269                 if(ai instanceof AAFAuthenticationInfo) {
270                         if(!((AAFAuthenticationInfo)ai).matches(atoken)) {
271                                 throw new AuthenticationException("Credentials do not match");
272                         }
273                         
274                 } else {
275                         throw new AuthenticationException("AuthenticationInfo is not an AAFAuthenticationInfo");
276                 
277                 }
278         }
279
280
281
282
283         @Override
284         protected AAFAuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
285                 Principal bait = (Principal)principals.getPrimaryPrincipal();
286                 Principal newBait = bait;
287                 if(singleton.idMap!=null) {
288                         final String newID = singleton.idMap.get(bait.getName());
289                         if(newID!=null) {
290                                 singleton.access.printf(Level.INFO,"Successful authentication Translation %s to %s",bait.getName(), newID); 
291                                 newBait = new Principal() {
292                                         @Override
293                                         public String getName() {
294                                                 return newID;
295                                         }
296                                 };
297                         }
298                 }
299                 List<Permission> pond = new ArrayList<>();
300                 singleton.authz.fishAll(newBait,pond);
301                 return new AAFAuthorizationInfo(singleton.access,bait,pond);
302         }
303
304         @Override
305         public boolean supports(AuthenticationToken token) {
306                 return singleton.supports.contains(token.getClass());
307         }
308
309         @Override
310         public String getName() {
311                 return AAF_REALM;
312         }
313
314 }