1
+ /*
2
+ * Copyright (C) 2014, Evolved Binary Ltd
3
+ *
4
+ * This file was originally ported from FusionDB to eXist-db by
5
+ * Evolved Binary, for the benefit of the eXist-db Open Source community.
6
+ * Only the ported code as it appears in this file, at the time that
7
+ * it was contributed to eXist-db, was re-licensed under The GNU
8
+ * Lesser General Public License v2.1 only for use in eXist-db.
9
+ *
10
+ * This license grant applies only to a snapshot of the code as it
11
+ * appeared when ported, it does not offer or infer any rights to either
12
+ * updates of this source code or access to the original source code.
13
+ *
14
+ * The GNU Lesser General Public License v2.1 only license follows.
15
+ *
16
+ * ---------------------------------------------------------------------
17
+ *
18
+ * Copyright (C) 2014, Evolved Binary Ltd
19
+ *
20
+ * This library is free software; you can redistribute it and/or
21
+ * modify it under the terms of the GNU Lesser General Public
22
+ * License as published by the Free Software Foundation; version 2.1.
23
+ *
24
+ * This library is distributed in the hope that it will be useful,
25
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
26
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27
+ * Lesser General Public License for more details.
28
+ *
29
+ * You should have received a copy of the GNU Lesser General Public
30
+ * License along with this library; if not, write to the Free Software
31
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
32
+ */
33
+ package org .exist .xquery .functions ;
34
+
35
+ import com .evolvedbinary .j8fu .tuple .Tuple2 ;
36
+ import io .lacuna .bifurcan .IMap ;
37
+ import io .lacuna .bifurcan .ISet ;
38
+ import io .lacuna .bifurcan .LinearSet ;
39
+ import io .lacuna .bifurcan .LinearMap ;
40
+ import io .lacuna .bifurcan .Map ;
41
+ import io .lacuna .bifurcan .Set ;
42
+ import org .exist .security .Subject ;
43
+ import org .exist .security .internal .SecurityManagerImpl ;
44
+
45
+ import java .util .List ;
46
+ import java .util .regex .Matcher ;
47
+ import java .util .regex .Pattern ;
48
+
49
+ import static com .evolvedbinary .j8fu .tuple .Tuple .Tuple ;
50
+
51
+ /**
52
+ * @author <a href="mailto:[email protected] ">Adam Retter</a>
53
+ */
54
+ public class AccessUtil {
55
+
56
+ static final String OTHERWISE = "*" ;
57
+
58
+ /**
59
+ * Parse access parameters into Group Access Rules and User Access Rules.
60
+ *
61
+ * @param accessRulePattern A pattern whose first group matches a "name",
62
+ * and whose second pattern matches the String "Group" or "User".
63
+ * @param parameters the module parameters.
64
+ *
65
+ * @return a Tuple where the first entry is the Group Access Rules, and the second entry is the User Access Rules.
66
+ */
67
+ public static Tuple2 <IMap <String , ISet <String >>, IMap <String , ISet <String >>> parseAccessParameters (
68
+ final Pattern accessRulePattern , final java .util .Map <String , List <?>> parameters ) {
69
+ IMap <String , ISet <String >> accessGroupRules = null ;
70
+ IMap <String , ISet <String >> accessUserRules = null ;
71
+
72
+ if (parameters != null ) {
73
+ Matcher matcher = null ;
74
+ for (final java .util .Map .Entry <String , List <?>> parameter : parameters .entrySet ()) {
75
+ final String parameterName = parameter .getKey ();
76
+ if (matcher == null ) {
77
+ matcher = accessRulePattern .matcher (parameterName );
78
+ } else {
79
+ matcher .reset (parameterName );
80
+ }
81
+
82
+ if (matcher .matches ()) {
83
+ final String principalType = matcher .group (2 );
84
+ if ("Group" .equals (principalType )) {
85
+ if (accessGroupRules == null ) {
86
+ accessGroupRules = new LinearMap <>();
87
+ }
88
+ final String name = matcher .group (1 );
89
+ accessGroupRules .put (name , toSet (parameter .getValue ()));
90
+ } else if ("User" .equals (principalType )) {
91
+ if (accessUserRules == null ) {
92
+ accessUserRules = new LinearMap <>();
93
+ }
94
+ final String name = matcher .group (1 );
95
+ accessUserRules .put (name , toSet (parameter .getValue ()));
96
+ }
97
+ }
98
+ }
99
+ }
100
+
101
+ if ((accessGroupRules == null || !accessGroupRules .contains (OTHERWISE ))
102
+ && ((accessUserRules == null ) || !accessUserRules .contains (OTHERWISE ))) {
103
+ if (accessGroupRules == null ) {
104
+ accessGroupRules = new LinearMap <>(1 );
105
+ ISet <String > otherwiseDba = new LinearSet <>(1 );
106
+ otherwiseDba .add (SecurityManagerImpl .DBA_GROUP );
107
+ otherwiseDba = otherwiseDba .forked ();
108
+ accessGroupRules .put (OTHERWISE , otherwiseDba );
109
+ }
110
+ }
111
+
112
+ if (accessGroupRules == null ) {
113
+ accessGroupRules = Map .empty ();
114
+ } else {
115
+ accessGroupRules = accessGroupRules .forked ();
116
+ }
117
+
118
+ if (accessUserRules == null ) {
119
+ accessUserRules = Map .empty ();
120
+ } else {
121
+ accessUserRules = accessUserRules .forked ();
122
+ }
123
+
124
+ return Tuple (accessGroupRules , accessUserRules );
125
+ }
126
+
127
+ private static ISet <String > toSet (final List <?> values ) {
128
+ ISet <String > set ;
129
+ if (values .size () > 0 ) {
130
+ set = new LinearSet <>();
131
+ for (final Object value : values ) {
132
+ set .add (value .toString ());
133
+ }
134
+ set = set .forked ();
135
+ } else {
136
+ set = Set .empty ();
137
+ }
138
+ return set ;
139
+ }
140
+
141
+ /**
142
+ * Returns true of the user is allowed access to the name.
143
+ *
144
+ * @param user the user to test the access rules against.
145
+ * @param accessGroupRules the group access rules.
146
+ * @param accessUserRules the user access rules.
147
+ * @param name the name of the resource that the user wishes to access.
148
+ */
149
+ public static boolean isAllowedAccess (final Subject user , final IMap <String , ISet <String >> accessGroupRules ,
150
+ final IMap <String , ISet <String >> accessUserRules , final String name ) {
151
+ return hasGroupAccess (user , accessGroupRules , name )
152
+ || hasUserAccess (user , accessUserRules , name );
153
+ }
154
+
155
+ private static boolean hasGroupAccess (final Subject user , final IMap <String , ISet <String >> accessGroupRules ,
156
+ final String name ) {
157
+ ISet <String > accessGroups = accessGroupRules .get (name , null );
158
+
159
+ // fallback to "otherwise"
160
+ if (accessGroups == null ) {
161
+ accessGroups = accessGroupRules .get (OTHERWISE , null );
162
+ }
163
+
164
+ if (accessGroups != null ) {
165
+ final String [] userGroups = user .getGroups ();
166
+ for (final String userGroup : userGroups ) {
167
+ if (accessGroups .contains (userGroup )) {
168
+ return true ;
169
+ }
170
+ }
171
+ }
172
+
173
+ return false ;
174
+ }
175
+
176
+ private static boolean hasUserAccess (final Subject user , final IMap <String , ISet <String >> accessUserRules ,
177
+ final String name ) {
178
+ ISet <String > accessUsers = accessUserRules .get (name , null );
179
+
180
+ // fallback to "otherwise"
181
+ if (accessUsers == null ) {
182
+ accessUsers = accessUserRules .get (OTHERWISE , null );
183
+ }
184
+
185
+ if (accessUsers != null ) {
186
+ return accessUsers .contains (user .getUsername ());
187
+ }
188
+
189
+ return false ;
190
+ }
191
+ }
0 commit comments