Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / sql / conn / GenericAuthorizer.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/conn/GenericAuthorizer.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/conn/GenericAuthorizer.java
new file mode 100644 (file)
index 0000000..1011068
--- /dev/null
@@ -0,0 +1,326 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.conn.GenericAuthorizer\r
+\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to you under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+      http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.sql.conn;\r
+\r
+import org.apache.derby.iapi.sql.Activation;\r
+import org.apache.derby.iapi.reference.Property;\r
+import org.apache.derby.iapi.util.IdUtil;\r
+import org.apache.derby.iapi.util.StringUtil;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.sql.conn.Authorizer;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+import org.apache.derby.iapi.services.property.PropertyUtil;\r
+import org.apache.derby.iapi.services.property.PersistentSet;\r
+import org.apache.derby.catalog.types.RoutineAliasInfo;\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+import org.apache.derby.iapi.sql.dictionary.StatementPermission;\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+\r
+import java.util.Properties;\r
+import java.util.List;\r
+import java.util.Iterator;\r
+\r
+class GenericAuthorizer\r
+implements Authorizer\r
+{\r
+       //\r
+       //Enumerations for user access levels.\r
+       private static final int NO_ACCESS = 0;\r
+       private static final int READ_ACCESS = 1;\r
+       private static final int FULL_ACCESS = 2;\r
+       \r
+       //\r
+       //Configurable userAccessLevel - derived from Database level\r
+       //access control lists + database boot time controls.\r
+       private int userAccessLevel;\r
+\r
+       //\r
+       //Connection's readOnly status\r
+    boolean readOnlyConnection;\r
+\r
+       private final LanguageConnectionContext lcc;\r
+       \r
+       private final String authorizationId; //the userName after parsing by IdUtil \r
+       \r
+       GenericAuthorizer(String authorizationId, \r
+                                                    LanguageConnectionContext lcc)\r
+                throws StandardException\r
+       {\r
+               this.lcc = lcc;\r
+               this.authorizationId = authorizationId;\r
+\r
+               refresh();\r
+       }\r
+\r
+       /*\r
+         Return true if the connection must remain readOnly\r
+         */\r
+       private boolean connectionMustRemainReadOnly()\r
+       {\r
+               if (lcc.getDatabase().isReadOnly() ||\r
+                       (userAccessLevel==READ_ACCESS))\r
+                       return true;\r
+               else\r
+                       return false;\r
+       }\r
+\r
+       /**\r
+         Used for operations that do not involve tables or routines.\r
+     \r
+         @see Authorizer#authorize\r
+         @exception StandardException Thrown if the operation is not allowed\r
+       */\r
+       public void authorize( int operation) throws StandardException\r
+       {\r
+               authorize( (Activation) null, operation);\r
+       }\r
+\r
+       /**\r
+         @see Authorizer#authorize\r
+         @exception StandardException Thrown if the operation is not allowed\r
+        */\r
+       public void authorize( Activation activation, int operation) throws StandardException\r
+       {\r
+               int sqlAllowed = lcc.getStatementContext().getSQLAllowed();\r
+\r
+               switch (operation)\r
+               {\r
+               case Authorizer.SQL_ARBITARY_OP:\r
+               case Authorizer.SQL_CALL_OP:\r
+                       if (sqlAllowed == RoutineAliasInfo.NO_SQL)\r
+                               throw externalRoutineException(operation, sqlAllowed);\r
+                       break;\r
+               case Authorizer.SQL_SELECT_OP:\r
+                       if (sqlAllowed > RoutineAliasInfo.READS_SQL_DATA)\r
+                               throw externalRoutineException(operation, sqlAllowed);\r
+                       break;\r
+\r
+               // SQL write operations\r
+               case Authorizer.SQL_WRITE_OP:\r
+               case Authorizer.PROPERTY_WRITE_OP:\r
+                       if (isReadOnlyConnection())\r
+                               throw StandardException.newException(SQLState.AUTH_WRITE_WITH_READ_ONLY_CONNECTION);\r
+                       if (sqlAllowed > RoutineAliasInfo.MODIFIES_SQL_DATA)\r
+                               throw externalRoutineException(operation, sqlAllowed);\r
+                       break;\r
+\r
+               // SQL DDL operations\r
+               case Authorizer.JAR_WRITE_OP:\r
+               case Authorizer.SQL_DDL_OP:\r
+                       if (isReadOnlyConnection())\r
+                               throw StandardException.newException(SQLState.AUTH_DDL_WITH_READ_ONLY_CONNECTION);\r
+\r
+                       if (sqlAllowed > RoutineAliasInfo.MODIFIES_SQL_DATA)\r
+                               throw externalRoutineException(operation, sqlAllowed);\r
+                       break;\r
+\r
+               default:\r
+                       if (SanityManager.DEBUG)\r
+                               SanityManager.THROWASSERT("Bad operation code "+operation);\r
+               }\r
+        if( activation != null)\r
+        {\r
+            List requiredPermissionsList = activation.getPreparedStatement().getRequiredPermissionsList();\r
+            DataDictionary dd = lcc.getDataDictionary();\r
+\r
+            // Database Owner can access any object. Ignore \r
+            // requiredPermissionsList for Database Owner\r
+            if( requiredPermissionsList != null    && \r
+                !requiredPermissionsList.isEmpty() && \r
+                               !authorizationId.equals(dd.getAuthorizationDatabaseOwner()))\r
+            {\r
+                int ddMode = dd.startReading(lcc);\r
+                \r
+                 /*\r
+                  * The system may need to read the permission descriptor(s) \r
+                  * from the system table(s) if they are not available in the \r
+                  * permission cache.  So start an internal read-only nested \r
+                  * transaction for this.\r
+                  * \r
+                  * The reason to use a nested transaction here is to not hold\r
+                  * locks on system tables on a user transaction.  e.g.:  when\r
+                  * attempting to revoke an user, the statement may time out\r
+                  * since the user-to-be-revoked transaction may have acquired \r
+                  * shared locks on the permission system tables; hence, this\r
+                  * may not be desirable.  \r
+                  * \r
+                  * All locks acquired by StatementPermission object's check()\r
+                  * method will be released when the system ends the nested \r
+                  * transaction.\r
+                  * \r
+                  * In Derby, the locks from read nested transactions come from\r
+                  * the same space as the parent transaction; hence, they do not\r
+                  * conflict with parent locks.\r
+                  */  \r
+                lcc.beginNestedTransaction(true);\r
+               \r
+                try \r
+                {\r
+                    try \r
+                    {\r
+                       // perform the permission checking\r
+                        for (Iterator iter = requiredPermissionsList.iterator(); \r
+                            iter.hasNext();) \r
+                        {\r
+                            ((StatementPermission) iter.next()).check(lcc, \r
+                                authorizationId, false);\r
+                        }\r
+                    } \r
+                    finally \r
+                    {\r
+                        dd.doneReading(ddMode, lcc);\r
+                    }\r
+                } \r
+                finally \r
+                {\r
+                       // make sure we commit; otherwise, we will end up with \r
+                       // mismatch nested level in the language connection context.\r
+                    lcc.commitNestedTransaction();\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+       private static StandardException externalRoutineException(int operation, int sqlAllowed) {\r
+\r
+               String sqlState;\r
+               if (sqlAllowed == RoutineAliasInfo.READS_SQL_DATA)\r
+                       sqlState = SQLState.EXTERNAL_ROUTINE_NO_MODIFIES_SQL;\r
+               else if (sqlAllowed == RoutineAliasInfo.CONTAINS_SQL)\r
+               {\r
+                       switch (operation)\r
+                       {\r
+                       case Authorizer.SQL_WRITE_OP:\r
+                       case Authorizer.PROPERTY_WRITE_OP:\r
+                       case Authorizer.JAR_WRITE_OP:\r
+                       case Authorizer.SQL_DDL_OP:\r
+                               sqlState = SQLState.EXTERNAL_ROUTINE_NO_MODIFIES_SQL;\r
+                               break;\r
+                       default:\r
+                               sqlState = SQLState.EXTERNAL_ROUTINE_NO_READS_SQL;\r
+                               break;\r
+                       }\r
+               }\r
+               else\r
+                       sqlState = SQLState.EXTERNAL_ROUTINE_NO_SQL;\r
+\r
+               return StandardException.newException(sqlState);\r
+       }\r
+       \r
+\r
+       /**\r
+         @see Authorizer#getAuthorizationId\r
+         */\r
+       public String getAuthorizationId()\r
+       {\r
+               return authorizationId;\r
+       }\r
+\r
+       private void getUserAccessLevel() throws StandardException\r
+       {\r
+               userAccessLevel = NO_ACCESS;\r
+               if (userOnAccessList(Property.FULL_ACCESS_USERS_PROPERTY))\r
+                       userAccessLevel = FULL_ACCESS;\r
+\r
+               if (userAccessLevel == NO_ACCESS &&\r
+                       userOnAccessList(Property.READ_ONLY_ACCESS_USERS_PROPERTY))\r
+                       userAccessLevel = READ_ACCESS;\r
+\r
+               if (userAccessLevel == NO_ACCESS)\r
+                       userAccessLevel = getDefaultAccessLevel();\r
+       }\r
+\r
+       private int getDefaultAccessLevel() throws StandardException\r
+       {\r
+               PersistentSet tc = lcc.getTransactionExecute();\r
+\r
+               String modeS = (String)\r
+                       PropertyUtil.getServiceProperty(\r
+                                                                       tc,\r
+                                                                       Property.DEFAULT_CONNECTION_MODE_PROPERTY);\r
+               if (modeS == null)\r
+                       return FULL_ACCESS;\r
+               else if(StringUtil.SQLEqualsIgnoreCase(modeS, Property.NO_ACCESS))\r
+                       return NO_ACCESS;\r
+               else if(StringUtil.SQLEqualsIgnoreCase(modeS, Property.READ_ONLY_ACCESS))\r
+                       return READ_ACCESS;\r
+               else if(StringUtil.SQLEqualsIgnoreCase(modeS, Property.FULL_ACCESS))\r
+                       return FULL_ACCESS;\r
+               else\r
+               {\r
+                       if (SanityManager.DEBUG)\r
+                               SanityManager.THROWASSERT("Invalid value for property "+\r
+                                                                                 Property.DEFAULT_CONNECTION_MODE_PROPERTY+\r
+                                                                                 " "+\r
+                                                                                 modeS);\r
+                       return FULL_ACCESS;\r
+               }\r
+       }\r
+\r
+       private boolean userOnAccessList(String listName) throws StandardException\r
+       {\r
+               PersistentSet tc = lcc.getTransactionExecute();\r
+               String listS = (String)\r
+                       PropertyUtil.getServiceProperty(tc, listName);\r
+               return IdUtil.idOnList(authorizationId,listS);\r
+       }\r
+\r
+       /**\r
+         @see Authorizer#isReadOnlyConnection\r
+        */\r
+       public boolean isReadOnlyConnection()\r
+       {\r
+               return readOnlyConnection;\r
+       }\r
+\r
+       /**\r
+         @see Authorizer#isReadOnlyConnection\r
+         @exception StandardException Thrown if the operation is not allowed\r
+        */\r
+       public void setReadOnlyConnection(boolean on, boolean authorize)\r
+                throws StandardException\r
+       {\r
+               if (authorize && !on) {\r
+                       if (connectionMustRemainReadOnly())\r
+                               throw StandardException.newException(SQLState.AUTH_CANNOT_SET_READ_WRITE);\r
+               }\r
+               readOnlyConnection = on;\r
+       }\r
+\r
+       /**\r
+         @see Authorizer#refresh\r
+         @exception StandardException Thrown if the operation is not allowed\r
+         */\r
+       public void refresh() throws StandardException\r
+       {\r
+               getUserAccessLevel();\r
+               if (!readOnlyConnection)\r
+                       readOnlyConnection = connectionMustRemainReadOnly();\r
+\r
+               // Is a connection allowed.\r
+               if (userAccessLevel == NO_ACCESS)\r
+                       throw StandardException.newException(SQLState.AUTH_DATABASE_CONNECTION_REFUSED);\r
+       }\r
+       \r
+}\r