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.ArrayList;
26 import java.util.List;
28 import java.util.Map.Entry;
30 import java.util.concurrent.ConcurrentHashMap;
31 import java.util.concurrent.ConcurrentSkipListSet;
33 import org.apache.shiro.authc.AuthenticationException;
34 import org.apache.shiro.authc.AuthenticationInfo;
35 import org.apache.shiro.authc.AuthenticationToken;
36 import org.apache.shiro.authc.UsernamePasswordToken;
37 import org.apache.shiro.realm.AuthorizingRealm;
38 import org.apache.shiro.subject.PrincipalCollection;
39 import org.onap.aaf.cadi.Access.Level;
40 import org.onap.aaf.cadi.CadiException;
41 import org.onap.aaf.cadi.LocatorException;
42 import org.onap.aaf.cadi.Permission;
43 import org.onap.aaf.cadi.PropAccess;
44 import org.onap.aaf.cadi.Symm;
45 import org.onap.aaf.cadi.aaf.v2_0.AAFAuthn;
46 import org.onap.aaf.cadi.aaf.v2_0.AAFCon;
47 import org.onap.aaf.cadi.aaf.v2_0.AAFLurPerm;
48 import org.onap.aaf.cadi.config.Config;
49 import org.onap.aaf.cadi.filter.MapBathConverter;
50 import org.onap.aaf.cadi.util.CSV;
51 import org.onap.aaf.misc.env.APIException;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
55 public class AAFRealm extends AuthorizingRealm {
56 public static final String AAF_REALM = "AAFRealm";
57 private static final Logger logger = LoggerFactory.getLogger(AAFRealm.class);
58 private static Singleton singleton = Singleton.singleton();
60 private static class Singleton {
61 private AAFCon<?> acon;
62 private AAFAuthn<?> authn;
63 private Set<Class<? extends AuthenticationToken>> supports;
64 private AAFLurPerm authz;
65 private MapBathConverter mbc;
66 private Map<String,String> idMap;
70 String cadi_prop_files = access.getProperty(Config.CADI_PROP_FILES);
71 if(cadi_prop_files==null) {
72 String msg = Config.CADI_PROP_FILES + " in VM Args is required to initialize AAFRealm.";
73 access.log(Level.INFO,msg);
74 throw new RuntimeException(msg);
77 acon = AAFCon.newInstance(access);
78 authn = acon.newAuthn();
79 authz = acon.newLur(authn);
81 final String csv = access.getProperty(Config.CADI_BATH_CONVERT);
84 mbc = new MapBathConverter(access, new CSV(csv));
85 access.log(Level.INFO, "MapBathConversion enabled with file ",csv);
86 idMap = new ConcurrentHashMap<String,String>();
88 for(Entry<String, String> es : mbc.map().entrySet()) {
89 String oldID = es.getKey();
90 if(oldID.startsWith("Basic ")) {
91 oldID = Symm.base64noSplit.decode(oldID.substring(6));
92 int idx = oldID.indexOf(':');
94 oldID = oldID.substring(0, idx);
97 String newID = es.getValue();
98 if(newID.startsWith("Basic ")) {
99 newID = Symm.base64noSplit.decode(newID.substring(6));
100 int idx = newID.indexOf(':');
102 newID = newID.substring(0, idx);
105 idMap.put(oldID,newID);
108 } catch (IOException e) {
112 } catch (APIException | CadiException | LocatorException e) {
113 String msg = "Cannot initiate AAFRealm";
114 access.log(Level.ERROR,e,msg);
115 throw new RuntimeException(msg,e);
118 supports = new ConcurrentSkipListSet<>();
119 supports.add(UsernamePasswordToken.class);
122 public static synchronized Singleton singleton() {
123 if(singleton==null) {
124 singleton = new Singleton();
129 // pick up cadi_prop_files from VM_Args
130 private final PropAccess access = new PropAccess() {
132 public void log(Exception e, Object... elements) {
133 logger.error(buildMsg(Level.ERROR, elements).toString(),e);
137 public void log(Level level, Object... elements) {
139 String str = buildMsg(level, elements).toString();
165 public void printf(Level level, String fmt, Object... elements) {
167 String str = String.format(fmt, elements);
193 public boolean willLog(Level level) {
194 if(super.willLog(level)) {
197 return logger.isWarnEnabled();
199 return logger.isDebugEnabled();
201 return logger.isErrorEnabled();
204 return logger.isInfoEnabled();
208 return logger.isTraceEnabled();
210 return logger.isWarnEnabled();
221 * There appears to be no configuration objects or references available for CADI to start with.
226 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
227 final UsernamePasswordToken upt = (UsernamePasswordToken)token;
228 final String user = upt.getUsername();
229 String authUser = user;
230 final String password=new String(upt.getPassword());
231 String authPassword = password;
232 if(singleton.mbc!=null) {
234 final String oldBath = "Basic " + Symm.base64noSplit.encode(user+':'+password);
235 String bath = singleton.mbc.convert(singleton.access, oldBath);
237 bath = Symm.base64noSplit.decode(bath.substring(6));
238 int colon = bath.indexOf(':');
240 authUser = bath.substring(0, colon);
241 authPassword = bath.substring(colon+1);
244 } catch (IOException e) {
245 singleton.access.log(e);
250 err = singleton.authn.validate(authUser,authPassword);
252 singleton.access.log(Level.INFO, err);
253 throw new AuthenticationException(err);
256 } catch (IOException e) {
257 singleton.access.log(e,"Credential cannot be validated");
260 return new AAFAuthenticationInfo(
268 protected void assertCredentialsMatch(AuthenticationToken atoken, AuthenticationInfo ai)throws AuthenticationException {
270 if(ai instanceof AAFAuthenticationInfo) {
271 if(!((AAFAuthenticationInfo)ai).matches(atoken)) {
272 throw new AuthenticationException("Credentials do not match");
276 throw new AuthenticationException("AuthenticationInfo is not an AAFAuthenticationInfo");
285 protected AAFAuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
286 Principal bait = (Principal)principals.getPrimaryPrincipal();
287 Principal newBait = bait;
288 if(singleton.idMap!=null) {
289 final String newID = singleton.idMap.get(bait.getName());
290 singleton.access.printf(Level.INFO,"Successful authentication attempt by %s",bait.getName());
292 newBait = new Principal() {
294 public String getName() {
300 List<Permission> pond = new ArrayList<>();
301 singleton.authz.fishAll(newBait,pond);
302 return new AAFAuthorizationInfo(singleton.access,bait,pond);
306 public boolean supports(AuthenticationToken token) {
307 return singleton.supports.contains(token.getClass());
311 public String getName() {