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====================================================
21 package org.onap.aaf.cadi.shiro;
23 import java.io.IOException;
24 import java.security.Principal;
25 import java.util.Collections;
26 import java.util.List;
28 import java.util.Map.Entry;
29 import java.util.TreeMap;
31 import org.apache.shiro.authc.AuthenticationException;
32 import org.apache.shiro.authc.AuthenticationInfo;
33 import org.apache.shiro.authc.AuthenticationToken;
34 import org.apache.shiro.authc.UsernamePasswordToken;
35 import org.apache.shiro.authz.AuthorizationInfo;
36 import org.apache.shiro.realm.AuthorizingRealm;
37 import org.apache.shiro.subject.PrincipalCollection;
38 import org.onap.aaf.cadi.Access.Level;
39 import org.onap.aaf.cadi.CadiException;
40 import org.onap.aaf.cadi.LocatorException;
41 import org.onap.aaf.cadi.PropAccess;
42 import org.onap.aaf.cadi.Symm;
43 import org.onap.aaf.cadi.aaf.AAFPermission;
44 import org.onap.aaf.cadi.aaf.v2_0.AAFAuthn;
45 import org.onap.aaf.cadi.aaf.v2_0.AAFCon;
46 import org.onap.aaf.cadi.aaf.v2_0.AAFLurPerm;
47 import org.onap.aaf.cadi.config.Config;
48 import org.onap.aaf.cadi.filter.MapBathConverter;
49 import org.onap.aaf.cadi.util.CSV;
50 import org.onap.aaf.cadi.util.Split;
51 import org.onap.aaf.misc.env.APIException;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
56 * Note: Shiro Realm document
57 * https://shiro.apache.org/realm.html
60 public class AAFRealm extends AuthorizingRealm {
61 public static final String AAF_REALM = "AAFRealm";
62 private static final Logger logger = LoggerFactory.getLogger(AAFRealm.class);
65 static Singleton singleton = Singleton.singleton();
67 public static class Singleton {
68 public AAFCon<?> acon;
69 public AAFAuthn<?> authn;
70 public AAFLurPerm authz;
71 // private Set<Class<? extends AuthenticationToken>> supports;
73 private MapBathConverter mbc;
74 private Map<String,String> idMap;
76 logger.info("Creating AAFRealm.Singleton");
79 String cadi_prop_files = access.getProperty(Config.CADI_PROP_FILES);
80 if(cadi_prop_files==null) {
81 String msg = Config.CADI_PROP_FILES + " in VM Args is required to initialize AAFRealm.";
82 access.log(Level.INFO,msg);
83 throw new RuntimeException(msg);
86 acon = AAFCon.newInstance(access);
87 authn = acon.newAuthn();
88 authz = acon.newLur(authn);
90 final String csv = access.getProperty(Config.CADI_BATH_CONVERT);
93 mbc = new MapBathConverter(access, new CSV(access,csv));
94 access.log(Level.INFO, "MapBathConversion enabled with file ",csv);
95 idMap = Collections.synchronizedMap(new TreeMap<String,String>());
97 for(Entry<String, String> es : mbc.map().entrySet()) {
98 String oldID = es.getKey();
99 if(oldID.startsWith("Basic ")) {
100 oldID = Symm.base64noSplit.decode(oldID.substring(6));
101 int idx = oldID.indexOf(':');
103 oldID = oldID.substring(0, idx);
106 String newID = es.getValue();
107 if(newID.startsWith("Basic ")) {
108 newID = Symm.base64noSplit.decode(newID.substring(6));
109 int idx = newID.indexOf(':');
111 newID = newID.substring(0, idx);
114 idMap.put(oldID,newID);
116 } catch (IOException e) {
120 } catch (APIException | CadiException | LocatorException e) {
121 String msg = "Cannot initiate AAFRealm";
122 access.log(Level.ERROR,e,msg);
123 throw new RuntimeException(msg,e);
127 // There is only one of these. If there are more, put back
128 // supports = Collections.synchronizedSet(new HashSet<>());
129 // supports.add(UsernamePasswordToken.class);
132 public static synchronized Singleton singleton() {
133 if(singleton==null) {
134 singleton = new Singleton();
139 // pick up cadi_prop_files from VM_Args
140 private final PropAccess access = new PropAccess() {
142 public void log(Exception e, Object... elements) {
143 logger.error(buildMsg(Level.ERROR, elements).toString(),e);
147 public void log(Level level, Object... elements) {
149 String str = buildMsg(level, elements).toString();
175 public void printf(Level level, String fmt, Object... elements) {
177 String str = String.format(fmt, elements);
203 public boolean willLog(Level level) {
204 if(super.willLog(level)) {
208 return logger.isWarnEnabled();
210 return logger.isDebugEnabled();
212 return logger.isErrorEnabled();
215 return logger.isInfoEnabled();
219 return logger.isTraceEnabled();
229 * There appears to be no configuration objects or references available for CADI to start with.
234 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
235 logger.debug("AAFRealm.doGetAuthenticationInfo");
236 final UsernamePasswordToken upt = (UsernamePasswordToken)token;
237 final String user = upt.getUsername();
238 String authUser = user;
239 final String password=new String(upt.getPassword());
240 String authPassword = password;
241 if(singleton.mbc!=null) {
243 final String oldBath = "Basic " + Symm.base64noSplit.encode(user+':'+password);
244 String bath = singleton.mbc.convert(singleton.access, oldBath);
246 bath = Symm.base64noSplit.decode(bath.substring(6));
247 int colon = bath.indexOf(':');
249 authUser = bath.substring(0, colon);
250 authPassword = bath.substring(colon+1);
253 } catch (IOException e) {
254 singleton.access.log(e);
259 err = singleton.authn.validate(authUser,authPassword);
261 singleton.access.log(Level.INFO, err);
262 throw new AuthenticationException(err);
265 } catch (IOException e) {
266 singleton.access.log(e,"Credential cannot be validated");
269 return new AAFAuthenticationInfo(
277 protected void assertCredentialsMatch(AuthenticationToken atoken, AuthenticationInfo ai)throws AuthenticationException {
278 logger.debug("AAFRealm.assertCredentialsMatch");
279 if(ai instanceof AAFAuthenticationInfo) {
280 if(!((AAFAuthenticationInfo)ai).matches(atoken)) {
281 throw new AuthenticationException("Credentials do not match");
284 throw new AuthenticationException("AuthenticationInfo is not an AAFAuthenticationInfo");
289 protected AAFAuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
290 logger.debug("AAFRealm.doGetAuthorizationInfo");
291 Principal bait = (Principal)principals.getPrimaryPrincipal();
292 Principal newBait = bait;
293 if(singleton.idMap!=null) {
294 final String newID = singleton.idMap.get(bait.getName());
296 singleton.access.printf(Level.INFO,"Successful authentication Translation %s to %s",bait.getName(), newID);
297 newBait = new Principal() {
299 public String getName() {
305 return new AAFAuthorizationInfo(singleton.access,newBait);
309 public boolean supports(AuthenticationToken token) {
310 // Only one was being loaded. If more are needed uncomment the multi-class mode
311 return token instanceof UsernamePasswordToken;
312 // return singleton.supports.contains(token.getClass());
316 public String getName() {
320 private AAFPermission aafPerm(String permission) {
321 String[] pa = Split.splitTrim('|', permission);
324 return new AAFPermission(null,pa[0],pa[1],pa[2]);
326 return new AAFPermission(pa[0],pa[1],pa[2],pa[3]);
333 public boolean isPermitted(PrincipalCollection principals, String permission) {
334 logger.debug("AAFRealm.isPermitted(principals,permission<String>)");
335 AAFPermission ap = aafPerm(permission);
337 return singleton.authz.fish((Principal)principals.getPrimaryPrincipal(), ap);
343 protected boolean isPermitted(org.apache.shiro.authz.Permission permission, AuthorizationInfo info) {
344 logger.debug("AAFRealm.isPermitted(shiro.Permission,AuthorizationInfo)");
345 if(info instanceof AAFAuthorizationInfo) {
346 AAFPermission ap = aafPerm(permission.toString());
348 return singleton.authz.fish(((AAFAuthorizationInfo)info).principal(), ap);
352 return super.isPermitted(permission, info);
356 protected boolean[] isPermitted(List<org.apache.shiro.authz.Permission> permissions, AuthorizationInfo info) {
357 logger.debug("AAFRealm.isPermitted(List<shiro.Permission>,AuthorizationInfo)");
358 if(info instanceof AAFAuthorizationInfo) {
359 boolean rv[] = new boolean[permissions.size()];
361 for(org.apache.shiro.authz.Permission sp : permissions) {
362 AAFPermission ap = aafPerm(sp.toString());
364 rv[i++]=singleton.authz.fish(((AAFAuthorizationInfo)info).principal(), ap);
371 return super.isPermitted(permissions, info);