Source code: org/apache/derby/impl/sql/conn/GenericAuthorizer.java
1 /*
2
3 Derby - Class org.apache.derby.impl.sql.conn.GenericAuthorizer
4
5 Copyright 1998, 2004 The Apache Software Foundation or its licensors, as applicable.
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
19 */
20
21 package org.apache.derby.impl.sql.conn;
22
23 import org.apache.derby.iapi.reference.Property;
24 import org.apache.derby.iapi.util.IdUtil;
25 import org.apache.derby.iapi.util.StringUtil;
26 import org.apache.derby.iapi.services.sanity.SanityManager;
27 import org.apache.derby.iapi.error.StandardException;
28 import org.apache.derby.iapi.sql.conn.Authorizer;
29 import org.apache.derby.iapi.reference.SQLState;
30 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
31 import org.apache.derby.iapi.services.property.PropertyUtil;
32 import org.apache.derby.iapi.services.property.PersistentSet;
33 import org.apache.derby.catalog.types.RoutineAliasInfo;
34 import java.util.Properties;
35
36 class GenericAuthorizer
37 implements Authorizer
38 {
39 //
40 //Enumerations for user access levels.
41 private static final int NO_ACCESS = 0;
42 private static final int READ_ACCESS = 1;
43 private static final int FULL_ACCESS = 2;
44
45 //
46 //Configurable userAccessLevel - derived from Database level
47 //access control lists + database boot time controls.
48 private int userAccessLevel;
49
50 //
51 //Connection's readOnly status
52 boolean readOnlyConnection;
53
54 private final LanguageConnectionContext lcc;
55
56 private final String authorizationId; //the userName after parsing by IdUtil
57
58 GenericAuthorizer(String authorizationId,
59 LanguageConnectionContext lcc,
60 boolean sqlConnection)
61 throws StandardException
62 {
63 this.lcc = lcc;
64 this.authorizationId = authorizationId;
65
66 //we check the access level only if this is coming from a sql
67 //connection, not internal logSniffer or StageTrunc db connection
68 if(sqlConnection)
69 refresh();
70 }
71
72 /*
73 Return true if the connection must remain readOnly
74 */
75 private boolean connectionMustRemainReadOnly()
76 {
77 if (lcc.getDatabase().isReadOnly() ||
78 (userAccessLevel==READ_ACCESS))
79 return true;
80 else
81 return false;
82 }
83
84 /**
85 @see Authorizer#authorize
86 @exception StandardException Thrown if the operation is not allowed
87 */
88 public void authorize(int operation) throws StandardException
89 {
90 int sqlAllowed = lcc.getStatementContext().getSQLAllowed();
91
92 switch (operation)
93 {
94 case Authorizer.SQL_ARBITARY_OP:
95 case Authorizer.SQL_CALL_OP:
96 if (sqlAllowed == RoutineAliasInfo.NO_SQL)
97 throw externalRoutineException(operation, sqlAllowed);
98 break;
99 case Authorizer.SQL_SELECT_OP:
100 if (sqlAllowed > RoutineAliasInfo.READS_SQL_DATA)
101 throw externalRoutineException(operation, sqlAllowed);
102 break;
103
104 // SQL write operations
105 case Authorizer.SQL_WRITE_OP:
106 case Authorizer.PROPERTY_WRITE_OP:
107 if (isReadOnlyConnection())
108 throw StandardException.newException(SQLState.AUTH_WRITE_WITH_READ_ONLY_CONNECTION);
109 if (sqlAllowed > RoutineAliasInfo.MODIFIES_SQL_DATA)
110 throw externalRoutineException(operation, sqlAllowed);
111 break;
112
113 // SQL DDL operations
114 case Authorizer.JAR_WRITE_OP:
115 case Authorizer.SQL_DDL_OP:
116 if (isReadOnlyConnection())
117 throw StandardException.newException(SQLState.AUTH_DDL_WITH_READ_ONLY_CONNECTION);
118
119 if (sqlAllowed > RoutineAliasInfo.MODIFIES_SQL_DATA)
120 throw externalRoutineException(operation, sqlAllowed);
121 break;
122
123 default:
124 if (SanityManager.DEBUG)
125 SanityManager.THROWASSERT("Bad operation code "+operation);
126 }
127 }
128
129 private static StandardException externalRoutineException(int operation, int sqlAllowed) {
130
131 String sqlState;
132 if (sqlAllowed == RoutineAliasInfo.READS_SQL_DATA)
133 sqlState = SQLState.EXTERNAL_ROUTINE_NO_MODIFIES_SQL;
134 else if (sqlAllowed == RoutineAliasInfo.CONTAINS_SQL)
135 {
136 switch (operation)
137 {
138 case Authorizer.SQL_WRITE_OP:
139 case Authorizer.PROPERTY_WRITE_OP:
140 case Authorizer.JAR_WRITE_OP:
141 case Authorizer.SQL_DDL_OP:
142 sqlState = SQLState.EXTERNAL_ROUTINE_NO_MODIFIES_SQL;
143 break;
144 default:
145 sqlState = SQLState.EXTERNAL_ROUTINE_NO_READS_SQL;
146 break;
147 }
148 }
149 else
150 sqlState = SQLState.EXTERNAL_ROUTINE_NO_SQL;
151
152 return StandardException.newException(sqlState);
153 }
154
155
156 /**
157 @see Authorizer#getAuthorizationId
158 */
159 public String getAuthorizationId()
160 {
161 return authorizationId;
162 }
163
164 private void getUserAccessLevel() throws StandardException
165 {
166 userAccessLevel = NO_ACCESS;
167 if (userOnAccessList(Property.FULL_ACCESS_USERS_PROPERTY))
168 userAccessLevel = FULL_ACCESS;
169
170 if (userAccessLevel == NO_ACCESS &&
171 userOnAccessList(Property.READ_ONLY_ACCESS_USERS_PROPERTY))
172 userAccessLevel = READ_ACCESS;
173
174 if (userAccessLevel == NO_ACCESS)
175 userAccessLevel = getDefaultAccessLevel();
176 }
177
178 private int getDefaultAccessLevel() throws StandardException
179 {
180 PersistentSet tc = lcc.getTransactionExecute();
181 String modeS = (String)
182 PropertyUtil.getServiceProperty(
183 tc,
184 Property.DEFAULT_CONNECTION_MODE_PROPERTY);
185 if (modeS == null)
186 return FULL_ACCESS;
187 else if(StringUtil.SQLEqualsIgnoreCase(modeS, Property.NO_ACCESS))
188 return NO_ACCESS;
189 else if(StringUtil.SQLEqualsIgnoreCase(modeS, Property.READ_ONLY_ACCESS))
190 return READ_ACCESS;
191 else if(StringUtil.SQLEqualsIgnoreCase(modeS, Property.FULL_ACCESS))
192 return FULL_ACCESS;
193 else
194 {
195 if (SanityManager.DEBUG)
196 SanityManager.THROWASSERT("Invalid value for property "+
197 Property.DEFAULT_CONNECTION_MODE_PROPERTY+
198 " "+
199 modeS);
200 return FULL_ACCESS;
201 }
202 }
203
204 private boolean userOnAccessList(String listName) throws StandardException
205 {
206 PersistentSet tc = lcc.getTransactionExecute();
207 String listS = (String)
208 PropertyUtil.getServiceProperty(tc, listName);
209 return IdUtil.idOnList(authorizationId,listS);
210 }
211
212 /**
213 @see Authorizer#isReadOnlyConnection
214 */
215 public boolean isReadOnlyConnection()
216 {
217 return readOnlyConnection;
218 }
219
220 /**
221 @see Authorizer#isReadOnlyConnection
222 @exception StandardException Thrown if the operation is not allowed
223 */
224 public void setReadOnlyConnection(boolean on, boolean authorize)
225 throws StandardException
226 {
227 if (authorize && !on) {
228 if (connectionMustRemainReadOnly())
229 throw StandardException.newException(SQLState.AUTH_CANNOT_SET_READ_WRITE);
230 }
231 readOnlyConnection = on;
232 }
233
234 /**
235 @see Authorizer#refresh
236 @exception StandardException Thrown if the operation is not allowed
237 */
238 public void refresh() throws StandardException
239 {
240 getUserAccessLevel();
241 if (!readOnlyConnection)
242 readOnlyConnection = connectionMustRemainReadOnly();
243
244 // Is a connection allowed.
245 if (userAccessLevel == NO_ACCESS)
246 throw StandardException.newException(SQLState.AUTH_DATABASE_CONNECTION_REFUSED);
247 }
248 }