2010-06-08 22 views
36

是否有可能在初始連接之後更改用戶在與postgres交互時使用的postgresql角色?連接到數據庫後切換角色

數據庫將用於Web應用程序,我想在連接池中使用表和模式的數據庫級規則。從閱讀postgresql文檔看來,如果我最初以具有超級用戶角色的用戶身份進行連接,則可以切換角色,但我更願意以最低權限進行連接,並根據需要進行切換。切換時必須指定用戶的密碼纔算正常(事實上,我更喜歡它)。

我錯過了什麼?

更新:我都試過SET ROLESET SESSION AUTHORIZATION通過@Milen的建議既不不過似乎命令,如果用戶不是超級用戶的工作:

$ psql -U test 
psql (8.4.4) 
Type "help" for help. 

test=> \du test 
      List of roles 
Role name | Attributes | Member of  
-----------+------------+---------------- 
test  |   | {connect_only} 

test=> \du test2 
      List of roles 
Role name | Attributes | Member of  
-----------+------------+---------------- 
test2  |   | {connect_only} 

test=> set role test2; 
ERROR: permission denied to set role "test2" 
test=> \q 

回答

7
+0

我試過兩個命令都無濟於事,如果連接用戶不是超級用戶,我得到權限被拒絕的錯誤。我已經用更多信息更新了這個問題 – 2010-06-09 01:58:00

+1

我相信你的用戶必須是你已經想要設置的角色的成員,並且在他們的用戶上擁有NOINHERITS屬性,以便他們不是默認的。那麼你應該升級和降級。但他們必須成爲這個角色的成員。 – rfusca 2010-06-09 03:26:12

30
--create a user that you want to use the database as: 

create role neil; 

--create the user for the web server to connect as: 

create role webgui noinherit login password 's3cr3t'; 

--let webgui set role to neil: 

grant neil to webgui; --this looks backwards but is correct. 

webgui現在是neil組中,所以webgui可以調用set role neil。但是,webgui未繼承neil的權限。

後來,作爲登錄的WebGUI:

psql -d some_database -U webgui 
(enter s3cr3t as password) 

set role neil; 

webgui並不需要爲這個superuser許可。

您想在數據庫會話開始時使用set role,並在會話結束時將其重置。在Web應用程序中,這對應於從數據庫連接池獲取連接並分別釋放它。以下是使用Tomcat的連接池和Spring Security的示例:

public class SetRoleJdbcInterceptor extends JdbcInterceptor { 

    @Override 
    public void reset(ConnectionPool connectionPool, PooledConnection pooledConnection) { 

     Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 

     if(authentication != null) { 
      try { 

       /* 
        use OWASP's ESAPI to encode the username to avoid SQL Injection. Can't use parameters with SET ROLE. Need to write PG codec. 

        Or use a whitelist-map approach 
       */ 
       String username = ESAPI.encoder().encodeForSQL(MY_CODEC, authentication.getName()); 

       Statement statement = pooledConnection.getConnection().createStatement(); 
       statement.execute("set role \"" + username + "\""); 
       statement.close(); 
      } catch(SQLException exp){ 
       throw new RuntimeException(exp); 
      } 
     } 
    } 

    @Override 
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 

     if("close".equals(method.getName())){ 
      Statement statement = ((Connection)proxy).createStatement(); 
      statement.execute("reset role"); 
      statement.close(); 
     } 

     return super.invoke(proxy, method, args); 
    } 
}