KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > sql > conn > GenericAuthorizer


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.conn.GenericAuthorizer
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.sql.conn;
23
24 import org.apache.derby.iapi.sql.Activation;
25 import org.apache.derby.iapi.reference.Property;
26 import org.apache.derby.iapi.util.IdUtil;
27 import org.apache.derby.iapi.util.StringUtil;
28 import org.apache.derby.iapi.services.sanity.SanityManager;
29 import org.apache.derby.iapi.error.StandardException;
30 import org.apache.derby.iapi.sql.conn.Authorizer;
31 import org.apache.derby.iapi.reference.SQLState;
32 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
33 import org.apache.derby.iapi.services.property.PropertyUtil;
34 import org.apache.derby.iapi.services.property.PersistentSet;
35 import org.apache.derby.catalog.types.RoutineAliasInfo;
36 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
37 import org.apache.derby.iapi.sql.dictionary.StatementPermission;
38 import org.apache.derby.iapi.store.access.TransactionController;
39
40 import java.util.Properties JavaDoc;
41 import java.util.List JavaDoc;
42 import java.util.Iterator JavaDoc;
43
44 class GenericAuthorizer
45 implements Authorizer
46 {
47     //
48
//Enumerations for user access levels.
49
private static final int NO_ACCESS = 0;
50     private static final int READ_ACCESS = 1;
51     private static final int FULL_ACCESS = 2;
52     
53     //
54
//Configurable userAccessLevel - derived from Database level
55
//access control lists + database boot time controls.
56
private int userAccessLevel;
57
58     //
59
//Connection's readOnly status
60
boolean readOnlyConnection;
61
62     private final LanguageConnectionContext lcc;
63     
64     private final String JavaDoc authorizationId; //the userName after parsing by IdUtil
65

66     GenericAuthorizer(String JavaDoc authorizationId,
67                              LanguageConnectionContext lcc,
68                              boolean sqlConnection)
69          throws StandardException
70     {
71         this.lcc = lcc;
72         this.authorizationId = authorizationId;
73
74         //we check the access level only if this is coming from a sql
75
//connection, not internal logSniffer or StageTrunc db connection
76
if(sqlConnection)
77             refresh();
78     }
79
80     /*
81       Return true if the connection must remain readOnly
82       */

83     private boolean connectionMustRemainReadOnly()
84     {
85         if (lcc.getDatabase().isReadOnly() ||
86             (userAccessLevel==READ_ACCESS))
87             return true;
88         else
89             return false;
90     }
91
92     /**
93       Used for operations that do not involve tables or routines.
94      
95       @see Authorizer#authorize
96       @exception StandardException Thrown if the operation is not allowed
97     */

98     public void authorize( int operation) throws StandardException
99     {
100         authorize( (Activation) null, operation);
101     }
102
103     /**
104       @see Authorizer#authorize
105       @exception StandardException Thrown if the operation is not allowed
106      */

107     public void authorize( Activation activation, int operation) throws StandardException
108     {
109         int sqlAllowed = lcc.getStatementContext().getSQLAllowed();
110
111         switch (operation)
112         {
113         case Authorizer.SQL_ARBITARY_OP:
114         case Authorizer.SQL_CALL_OP:
115             if (sqlAllowed == RoutineAliasInfo.NO_SQL)
116                 throw externalRoutineException(operation, sqlAllowed);
117             break;
118         case Authorizer.SQL_SELECT_OP:
119             if (sqlAllowed > RoutineAliasInfo.READS_SQL_DATA)
120                 throw externalRoutineException(operation, sqlAllowed);
121             break;
122
123         // SQL write operations
124
case Authorizer.SQL_WRITE_OP:
125         case Authorizer.PROPERTY_WRITE_OP:
126             if (isReadOnlyConnection())
127                 throw StandardException.newException(SQLState.AUTH_WRITE_WITH_READ_ONLY_CONNECTION);
128             if (sqlAllowed > RoutineAliasInfo.MODIFIES_SQL_DATA)
129                 throw externalRoutineException(operation, sqlAllowed);
130             break;
131
132         // SQL DDL operations
133
case Authorizer.JAR_WRITE_OP:
134         case Authorizer.SQL_DDL_OP:
135             if (isReadOnlyConnection())
136                 throw StandardException.newException(SQLState.AUTH_DDL_WITH_READ_ONLY_CONNECTION);
137
138             if (sqlAllowed > RoutineAliasInfo.MODIFIES_SQL_DATA)
139                 throw externalRoutineException(operation, sqlAllowed);
140             break;
141
142         default:
143             if (SanityManager.DEBUG)
144                 SanityManager.THROWASSERT("Bad operation code "+operation);
145         }
146         if( activation != null)
147         {
148             List JavaDoc requiredPermissionsList = activation.getPreparedStatement().getRequiredPermissionsList();
149             DataDictionary dd = lcc.getDataDictionary();
150
151             // Database Owner can access any object. Ignore
152
// requiredPermissionsList for Database Owner
153
if( requiredPermissionsList != null &&
154                 !requiredPermissionsList.isEmpty() &&
155                 !authorizationId.equals(dd.getAuthorizationDatabaseOwner()))
156             {
157                 int ddMode = dd.startReading(lcc);
158                 
159                  /*
160                   * The system may need to read the permission descriptor(s)
161                   * from the system table(s) if they are not available in the
162                   * permission cache. So start an internal read-only nested
163                   * transaction for this.
164                   *
165                   * The reason to use a nested transaction here is to not hold
166                   * locks on system tables on a user transaction. e.g.: when
167                   * attempting to revoke an user, the statement may time out
168                   * since the user-to-be-revoked transaction may have acquired
169                   * shared locks on the permission system tables; hence, this
170                   * may not be desirable.
171                   *
172                   * All locks acquired by StatementPermission object's check()
173                   * method will be released when the system ends the nested
174                   * transaction.
175                   *
176                   * In Derby, the locks from read nested transactions come from
177                   * the same space as the parent transaction; hence, they do not
178                   * conflict with parent locks.
179                   */

180                 lcc.beginNestedTransaction(true);
181                 
182                 try
183                 {
184                     try
185                     {
186                         // perform the permission checking
187
for (Iterator JavaDoc iter = requiredPermissionsList.iterator();
188                             iter.hasNext();)
189                         {
190                             ((StatementPermission) iter.next()).check(lcc,
191                                 authorizationId, false);
192                         }
193                     }
194                     finally
195                     {
196                         dd.doneReading(ddMode, lcc);
197                     }
198                 }
199                 finally
200                 {
201                     // make sure we commit; otherwise, we will end up with
202
// mismatch nested level in the language connection context.
203
lcc.commitNestedTransaction();
204                 }
205             }
206         }
207     }
208
209     private static StandardException externalRoutineException(int operation, int sqlAllowed) {
210
211         String JavaDoc sqlState;
212         if (sqlAllowed == RoutineAliasInfo.READS_SQL_DATA)
213             sqlState = SQLState.EXTERNAL_ROUTINE_NO_MODIFIES_SQL;
214         else if (sqlAllowed == RoutineAliasInfo.CONTAINS_SQL)
215         {
216             switch (operation)
217             {
218             case Authorizer.SQL_WRITE_OP:
219             case Authorizer.PROPERTY_WRITE_OP:
220             case Authorizer.JAR_WRITE_OP:
221             case Authorizer.SQL_DDL_OP:
222                 sqlState = SQLState.EXTERNAL_ROUTINE_NO_MODIFIES_SQL;
223                 break;
224             default:
225                 sqlState = SQLState.EXTERNAL_ROUTINE_NO_READS_SQL;
226                 break;
227             }
228         }
229         else
230             sqlState = SQLState.EXTERNAL_ROUTINE_NO_SQL;
231
232         return StandardException.newException(sqlState);
233     }
234     
235
236     /**
237       @see Authorizer#getAuthorizationId
238       */

239     public String JavaDoc getAuthorizationId()
240     {
241         return authorizationId;
242     }
243
244     private void getUserAccessLevel() throws StandardException
245     {
246         userAccessLevel = NO_ACCESS;
247         if (userOnAccessList(Property.FULL_ACCESS_USERS_PROPERTY))
248             userAccessLevel = FULL_ACCESS;
249
250         if (userAccessLevel == NO_ACCESS &&
251             userOnAccessList(Property.READ_ONLY_ACCESS_USERS_PROPERTY))
252             userAccessLevel = READ_ACCESS;
253
254         if (userAccessLevel == NO_ACCESS)
255             userAccessLevel = getDefaultAccessLevel();
256     }
257
258     private int getDefaultAccessLevel() throws StandardException
259     {
260         PersistentSet tc = lcc.getTransactionExecute();
261
262         String JavaDoc modeS = (String JavaDoc)
263             PropertyUtil.getServiceProperty(
264                                     tc,
265                                     Property.DEFAULT_CONNECTION_MODE_PROPERTY);
266         if (modeS == null)
267             return FULL_ACCESS;
268         else if(StringUtil.SQLEqualsIgnoreCase(modeS, Property.NO_ACCESS))
269             return NO_ACCESS;
270         else if(StringUtil.SQLEqualsIgnoreCase(modeS, Property.READ_ONLY_ACCESS))
271             return READ_ACCESS;
272         else if(StringUtil.SQLEqualsIgnoreCase(modeS, Property.FULL_ACCESS))
273             return FULL_ACCESS;
274         else
275         {
276             if (SanityManager.DEBUG)
277                 SanityManager.THROWASSERT("Invalid value for property "+
278                                           Property.DEFAULT_CONNECTION_MODE_PROPERTY+
279                                           " "+
280                                           modeS);
281             return FULL_ACCESS;
282         }
283     }
284
285     private boolean userOnAccessList(String JavaDoc listName) throws StandardException
286     {
287         PersistentSet tc = lcc.getTransactionExecute();
288         String JavaDoc listS = (String JavaDoc)
289             PropertyUtil.getServiceProperty(tc, listName);
290         return IdUtil.idOnList(authorizationId,listS);
291     }
292
293     /**
294       @see Authorizer#isReadOnlyConnection
295      */

296     public boolean isReadOnlyConnection()
297     {
298         return readOnlyConnection;
299     }
300
301     /**
302       @see Authorizer#isReadOnlyConnection
303       @exception StandardException Thrown if the operation is not allowed
304      */

305     public void setReadOnlyConnection(boolean on, boolean authorize)
306          throws StandardException
307     {
308         if (authorize && !on) {
309             if (connectionMustRemainReadOnly())
310                 throw StandardException.newException(SQLState.AUTH_CANNOT_SET_READ_WRITE);
311         }
312         readOnlyConnection = on;
313     }
314
315     /**
316       @see Authorizer#refresh
317       @exception StandardException Thrown if the operation is not allowed
318       */

319     public void refresh() throws StandardException
320     {
321         getUserAccessLevel();
322         if (!readOnlyConnection)
323             readOnlyConnection = connectionMustRemainReadOnly();
324
325         // Is a connection allowed.
326
if (userAccessLevel == NO_ACCESS)
327             throw StandardException.newException(SQLState.AUTH_DATABASE_CONNECTION_REFUSED);
328     }
329     
330 }
331
Popular Tags