1+ /*
2+ * Licensed to the Apache Software Foundation (ASF) under one or more
3+ * contributor license agreements. See the NOTICE file distributed with
4+ * this work for additional information regarding copyright ownership.
5+ * The ASF licenses this file to You under the Apache License, Version 2.0
6+ * (the "License"); you may not use this file except in compliance with
7+ * the License. You may obtain a copy of the License at
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+ package org .apache .karaf .jaas .modules ;
17+
18+ import org .apache .felix .utils .properties .Properties ;
19+ import org .apache .karaf .jaas .boot .principal .GroupPrincipal ;
20+ import org .apache .karaf .jaas .boot .principal .RolePrincipal ;
21+ import org .apache .karaf .jaas .boot .principal .UserPrincipal ;
22+ import org .slf4j .Logger ;
23+ import org .slf4j .LoggerFactory ;
24+ import java .security .Principal ;
25+ import java .util .ArrayList ;
26+ import java .util .HashMap ;
27+ import java .util .List ;
28+ import java .util .Map ;
29+
30+ public abstract class AbstractPropertiesBackingEngine implements BackingEngine {
31+
32+ private static final Logger LOGGER = LoggerFactory .getLogger (AbstractPropertiesBackingEngine .class );
33+
34+ private Properties users ;
35+
36+ public AbstractPropertiesBackingEngine (Properties users ) {
37+ this .users = users ;
38+ }
39+
40+ protected void addUserInternal (String username , String encPassword ) {
41+ String [] infos = null ;
42+ StringBuilder userInfoBuffer = new StringBuilder ();
43+
44+ String userInfos = users .get (username );
45+
46+ //If user already exists, update password
47+ if (userInfos != null && userInfos .length () > 0 ) {
48+ infos = userInfos .split ("," );
49+ userInfoBuffer .append (encPassword );
50+
51+ for (int i = 1 ; i < infos .length ; i ++) {
52+ userInfoBuffer .append ("," );
53+ userInfoBuffer .append (infos [i ]);
54+ }
55+ String newUserInfo = userInfoBuffer .toString ();
56+ users .put (username , newUserInfo );
57+ } else {
58+ users .put (username , encPassword );
59+ }
60+
61+ try {
62+ users .save ();
63+ } catch (Exception ex ) {
64+ LOGGER .error ("Cannot update users file," , ex );
65+ }
66+ }
67+
68+ @ Override
69+ public void deleteUser (String username ) {
70+ // delete all its groups first, for garbage collection of the groups
71+ for (GroupPrincipal gp : listGroups (username )) {
72+ deleteGroup (username , gp .getName ());
73+ }
74+
75+ users .remove (username );
76+
77+ try {
78+ users .save ();
79+ } catch (Exception ex ) {
80+ LOGGER .error ("Cannot remove users file," , ex );
81+ }
82+ }
83+
84+ @ Override
85+ public List <UserPrincipal > listUsers () {
86+ List <UserPrincipal > result = new ArrayList <>();
87+
88+ for (Object user : users .keySet ()) {
89+ String userName = (String ) user ;
90+ if (userName .startsWith (GROUP_PREFIX ))
91+ continue ;
92+
93+ UserPrincipal userPrincipal = new UserPrincipal (userName );
94+ result .add (userPrincipal );
95+ }
96+ return result ;
97+ }
98+
99+ @ Override
100+ public UserPrincipal lookupUser (String username ) {
101+ for (UserPrincipal userPrincipal : listUsers ()) {
102+ if (userPrincipal .getName ().equals (username )) {
103+ return userPrincipal ;
104+ }
105+ }
106+ return null ;
107+ }
108+
109+ @ Override
110+ public List <RolePrincipal > listRoles (Principal principal ) {
111+ String userName = principal .getName ();
112+ if (principal instanceof GroupPrincipal ) {
113+ userName = GROUP_PREFIX + userName ;
114+ }
115+ return listRoles (userName );
116+ }
117+
118+ protected List <RolePrincipal > listRoles (String name ) {
119+
120+ List <RolePrincipal > result = new ArrayList <>();
121+ String userInfo = users .get (name );
122+ String [] infos = userInfo .split ("," );
123+ for (int i = JAASUtils .getFirstRoleIndex (name ); i < infos .length ; i ++) {
124+ String roleName = infos [i ];
125+ if (roleName .trim ().isEmpty ())
126+ continue ;
127+ if (roleName .startsWith (GROUP_PREFIX )) {
128+ for (RolePrincipal rp : listRoles (roleName )) {
129+ if (!result .contains (rp )) {
130+ result .add (rp );
131+ }
132+ }
133+ } else {
134+ RolePrincipal rp = new RolePrincipal (roleName );
135+ if (!result .contains (rp )) {
136+ result .add (rp );
137+ }
138+ }
139+ }
140+ return result ;
141+ }
142+
143+ @ Override
144+ public void addRole (String username , String role ) {
145+ String userInfos = users .get (username );
146+ if (userInfos != null ) {
147+ // for groups, empty info should be replaced with role
148+ // for users, empty info means empty password and role should be appended
149+ if (userInfos .trim ().isEmpty ()
150+ && username .trim ().startsWith (AbstractPropertiesBackingEngine .GROUP_PREFIX )) {
151+ users .put (username , role );
152+ } else {
153+ for (RolePrincipal rp : listRoles (username )) {
154+ if (role .equals (rp .getName ())) {
155+ return ;
156+ }
157+ }
158+ for (GroupPrincipal gp : listGroups (username )) {
159+ if (role .equals (GROUP_PREFIX + gp .getName ())) {
160+ return ;
161+ }
162+ }
163+ String newUserInfos = userInfos + "," + role ;
164+ users .put (username , newUserInfos );
165+ }
166+ }
167+ try {
168+ users .save ();
169+ } catch (Exception ex ) {
170+ LOGGER .error ("Cannot update users file," , ex );
171+ }
172+ }
173+
174+ @ Override
175+ public void deleteRole (String username , String role ) {
176+ String [] infos = null ;
177+ StringBuilder userInfoBuffer = new StringBuilder ();
178+
179+ String userInfos = users .get (username );
180+
181+ //If user already exists, remove the role
182+ if (userInfos != null && userInfos .length () > 0 ) {
183+ infos = userInfos .split ("," );
184+
185+ int firstRoleIndex = JAASUtils .getFirstRoleIndex (username );
186+ if (firstRoleIndex == 1 ) {// index 0 is password
187+ String password = infos [0 ];
188+ userInfoBuffer .append (password );
189+ }
190+ for (int i = firstRoleIndex ; i < infos .length ; i ++) {
191+ if (infos [i ] != null && !infos [i ].equals (role )) {
192+ if (userInfoBuffer .length () > 0 ) {
193+ userInfoBuffer .append ("," );
194+ }
195+ userInfoBuffer .append (infos [i ]);
196+ }
197+ }
198+ String newUserInfo = userInfoBuffer .toString ();
199+ users .put (username , newUserInfo );
200+ }
201+
202+ try {
203+ users .save ();
204+ } catch (Exception ex ) {
205+ LOGGER .error ("Cannot update users file," , ex );
206+ }
207+ }
208+
209+ @ Override
210+ public List <GroupPrincipal > listGroups (UserPrincipal user ) {
211+ String userName = user .getName ();
212+ return listGroups (userName );
213+ }
214+
215+ private List <GroupPrincipal > listGroups (String userName ) {
216+ List <GroupPrincipal > result = new ArrayList <>();
217+ String userInfo = users .get (userName );
218+ if (userInfo != null ) {
219+ String [] infos = userInfo .split ("," );
220+ for (int i = JAASUtils .getFirstRoleIndex (userName ); i < infos .length ; i ++) {
221+ String name = infos [i ];
222+ if (name .startsWith (GROUP_PREFIX )) {
223+ result .add (new GroupPrincipal (name .substring (GROUP_PREFIX .length ())));
224+ }
225+ }
226+ }
227+ return result ;
228+ }
229+
230+ @ Override
231+ public void addGroup (String username , String group ) {
232+ String groupName = GROUP_PREFIX + group ;
233+ if (users .get (groupName ) == null ) {
234+ addUserInternal (groupName , "" ); // groups don't have password
235+ }
236+ addRole (username , groupName );
237+ }
238+
239+ @ Override
240+ public void deleteGroup (String username , String group ) {
241+ deleteRole (username , GROUP_PREFIX + group );
242+
243+ // garbage collection, clean up the groups if needed
244+ for (UserPrincipal user : listUsers ()) {
245+ for (GroupPrincipal g : listGroups (user )) {
246+ if (group .equals (g .getName ())) {
247+ // there is another user of this group, nothing to clean up
248+ return ;
249+ }
250+ }
251+ }
252+
253+ // nobody is using this group any more, remove it
254+ deleteUser (GROUP_PREFIX + group );
255+ }
256+
257+ @ Override
258+ public void addGroupRole (String group , String role ) {
259+ addRole (GROUP_PREFIX + group , role );
260+ }
261+
262+ @ Override
263+ public void deleteGroupRole (String group , String role ) {
264+ deleteRole (GROUP_PREFIX + group , role );
265+ }
266+
267+ public Map <GroupPrincipal , String > listGroups () {
268+ Map <GroupPrincipal , String > result = new HashMap <>();
269+ for (String name : users .keySet ()) {
270+ if (name .startsWith (GROUP_PREFIX )) {
271+ result .put (new GroupPrincipal (name .substring (GROUP_PREFIX .length ())), users .get (name ));
272+ }
273+ }
274+ return result ;
275+ }
276+
277+ @ Override
278+ public void createGroup (String group ) {
279+ String groupName = GROUP_PREFIX + group ;
280+ if (users .get (groupName ) == null ) {
281+ addUserInternal (groupName , "" ); // groups don't have password
282+ } else {
283+ throw new IllegalArgumentException ("Group: " + group + " already exist" );
284+ }
285+ }
286+ }
0 commit comments