trinodb / trino

Official repository of Trino, the distributed SQL query engine for big data, formerly known as PrestoSQL (https://trino.io)
https://trino.io
Apache License 2.0
9.94k stars 2.87k forks source link

Catalog level property to send user/password to SQLServer connector WITHOUT sending extraCredentials #8493

Open rsaw4 opened 3 years ago

rsaw4 commented 3 years ago

Presto connecting to a SQLServer catalog (with end user creds) works when extraCredentials of user:password is passed in, but not all clients support extraCredentials. Would be great to have a catalog level property set in the properties file to do this ie passthroughAuth=true

Below is error without extraCredentials being passed:

io.prestosql.spi.PrestoException: Kerberos Login failed: Integrated authentication failed. ClientConnectionId:cfd45ed8-e590-42bc-a830-f11c62f3fae3 due to javax.security.auth.login.LoginException (Cannot get any of properties: [user, USER] from con properties not available to garner  authentication information  from the user)
    at io.prestosql.plugin.jdbc.BaseJdbcClient.getTableHandle(BaseJdbcClient.java:240)
    at io.prestosql.plugin.jdbc.ForwardingJdbcClient.getTableHandle(ForwardingJdbcClient.java:76)
    at io.prestosql.plugin.jdbc.jmx.StatisticsAwareJdbcClient.lambda$getTableHandle$3(StatisticsAwareJdbcClient.java:91)
    at io.prestosql.plugin.jdbc.jmx.JdbcApiStats.wrap(JdbcApiStats.java:35)
    at io.prestosql.plugin.jdbc.jmx.StatisticsAwareJdbcClient.getTableHandle(StatisticsAwareJdbcClient.java:91)
    at io.prestosql.plugin.jdbc.CachingJdbcClient.getTableHandle(CachingJdbcClient.java:177)
    at io.prestosql.plugin.jdbc.JdbcMetadata.getTableHandle(JdbcMetadata.java:88)
    at io.prestosql.plugin.jdbc.JdbcMetadata.getTableHandle(JdbcMetadata.java:59)
    at io.prestosql.metadata.MetadataManager.getTableHandle(MetadataManager.java:339)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.visitTable(StatementAnalyzer.java:1033)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.visitTable(StatementAnalyzer.java:306)
    at io.prestosql.sql.tree.Table.accept(Table.java:53)
    at io.prestosql.sql.tree.AstVisitor.process(AstVisitor.java:27)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.process(StatementAnalyzer.java:323)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.analyzeFrom(StatementAnalyzer.java:2334)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.visitQuerySpecification(StatementAnalyzer.java:1284)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.visitQuerySpecification(StatementAnalyzer.java:306)
    at io.prestosql.sql.tree.QuerySpecification.accept(QuerySpecification.java:144)
    at io.prestosql.sql.tree.AstVisitor.process(AstVisitor.java:27)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.process(StatementAnalyzer.java:323)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.process(StatementAnalyzer.java:333)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.visitQuery(StatementAnalyzer.java:918)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.visitQuery(StatementAnalyzer.java:306)
    at io.prestosql.sql.tree.Query.accept(Query.java:107)
    at io.prestosql.sql.tree.AstVisitor.process(AstVisitor.java:27)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.process(StatementAnalyzer.java:323)
    at io.prestosql.sql.analyzer.StatementAnalyzer.analyze(StatementAnalyzer.java:292)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.visitTableSubquery(StatementAnalyzer.java:1274)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.visitTableSubquery(StatementAnalyzer.java:306)
    at io.prestosql.sql.tree.TableSubquery.accept(TableSubquery.java:53)
    at io.prestosql.sql.tree.AstVisitor.process(AstVisitor.java:27)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.process(StatementAnalyzer.java:323)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.analyzeFrom(StatementAnalyzer.java:2334)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.visitQuerySpecification(StatementAnalyzer.java:1284)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.visitQuerySpecification(StatementAnalyzer.java:306)
    at io.prestosql.sql.tree.QuerySpecification.accept(QuerySpecification.java:144)
    at io.prestosql.sql.tree.AstVisitor.process(AstVisitor.java:27)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.process(StatementAnalyzer.java:323)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.lambda$visitSetOperation$20(StatementAnalyzer.java:1359)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)
    at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Unknown Source)
    at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(Unknown Source)
    at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source)
    at java.base/java.util.stream.ReferencePipeline.collect(Unknown Source)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.visitSetOperation(StatementAnalyzer.java:1362)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.visitSetOperation(StatementAnalyzer.java:306)
    at io.prestosql.sql.tree.AstVisitor.visitUnion(AstVisitor.java:252)
    at io.prestosql.sql.tree.Union.accept(Union.java:57)
    at io.prestosql.sql.tree.AstVisitor.process(AstVisitor.java:27)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.process(StatementAnalyzer.java:323)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.process(StatementAnalyzer.java:333)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.visitQuery(StatementAnalyzer.java:918)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.visitQuery(StatementAnalyzer.java:306)
    at io.prestosql.sql.tree.Query.accept(Query.java:107)
    at io.prestosql.sql.tree.AstVisitor.process(AstVisitor.java:27)
    at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.process(StatementAnalyzer.java:323)
    at io.prestosql.sql.analyzer.StatementAnalyzer.analyze(StatementAnalyzer.java:292)
    at io.prestosql.sql.analyzer.Analyzer.analyze(Analyzer.java:83)
    at io.prestosql.sql.analyzer.Analyzer.analyze(Analyzer.java:75)
    at io.prestosql.execution.SqlQueryExecution.analyze(SqlQueryExecution.java:237)
    at io.prestosql.execution.SqlQueryExecution.<init>(SqlQueryExecution.java:183)
    at io.prestosql.execution.SqlQueryExecution$SqlQueryExecutionFactory.createQueryExecution(SqlQueryExecution.java:737)
    at io.prestosql.dispatcher.LocalDispatchQueryFactory.lambda$createDispatchQuery$0(LocalDispatchQueryFactory.java:121)
    at io.prestosql.$gen.Presto_20f5dc9____20210708_014058_2.call(Unknown Source)
    at com.google.common.util.concurrent.TrustedListenableFutureTask$TrustedFutureInterruptibleTask.runInterruptibly(TrustedListenableFutureTask.java:125)
    at com.google.common.util.concurrent.InterruptibleTask.run(InterruptibleTask.java:69)
    at com.google.common.util.concurrent.TrustedListenableFutureTask.run(TrustedListenableFutureTask.java:78)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.base/java.lang.Thread.run(Unknown Source)
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Kerberos Login failed: Integrated authentication failed. ClientConnectionId:cfd45ed8-e590-42bc-a830-f11c62f3fae3 due to javax.security.auth.login.LoginException (Cannot get any of properties: [user, USER] from con properties not available to garner  authentication information  from the user)
    at com.microsoft.sqlserver.jdbc.KerbAuthentication.intAuthInit(KerbAuthentication.java:110)
    at com.microsoft.sqlserver.jdbc.KerbAuthentication.GenerateClientContext(KerbAuthentication.java:391)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.sendLogon(SQLServerConnection.java:4525)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.logon(SQLServerConnection.java:3581)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.access$000(SQLServerConnection.java:81)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection$LogonCommand.doExecute(SQLServerConnection.java:3541)
    at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:7240)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:2869)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectHelper(SQLServerConnection.java:2395)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.login(SQLServerConnection.java:2042)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectInternal(SQLServerConnection.java:1889)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.connect(SQLServerConnection.java:1120)
    at com.microsoft.sqlserver.jdbc.SQLServerDriver.connect(SQLServerDriver.java:700)
    at io.prestosql.plugin.jdbc.DriverConnectionFactory.openConnection(DriverConnectionFactory.java:73)
    at io.prestosql.plugin.jdbc.jmx.StatisticsAwareConnectionFactory.lambda$openConnection$0(StatisticsAwareConnectionFactory.java:42)
    at io.prestosql.plugin.jdbc.jmx.JdbcApiStats.wrap(JdbcApiStats.java:35)
    at io.prestosql.plugin.jdbc.jmx.StatisticsAwareConnectionFactory.openConnection(StatisticsAwareConnectionFactory.java:42)
    at io.prestosql.plugin.jdbc.BaseJdbcClient.getTableHandle(BaseJdbcClient.java:218)
    ... 71 more
Caused by: javax.security.auth.login.LoginException: Cannot get any of properties: [user, USER] from con properties not available to garner  authentication information  from the user
    at jdk.security.auth/com.sun.security.auth.module.Krb5LoginModule.promptForName(Unknown Source)
    at jdk.security.auth/com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Unknown Source)
    at jdk.security.auth/com.sun.security.auth.module.Krb5LoginModule.login(Unknown Source)
    at java.base/javax.security.auth.login.LoginContext.invoke(Unknown Source)
    at java.base/javax.security.auth.login.LoginContext$4.run(Unknown Source)
    at java.base/javax.security.auth.login.LoginContext$4.run(Unknown Source)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at java.base/javax.security.auth.login.LoginContext.invokePriv(Unknown Source)
    at java.base/javax.security.auth.login.LoginContext.login(Unknown Source)
    at com.microsoft.sqlserver.jdbc.KerbAuthentication.intAuthInit(KerbAuthentication.java:87)
tooptoop4 commented 3 years ago

this solves it:

(patched on v336) --> presto-main\src\main\java\io\prestosql\server\HttpRequestSessionContext.java

private static Map<String, String> parseProperty(MultivaluedMap<String, String> headers, String headerName)
    {
        Map<String, String> properties = new HashMap<>();
        for (String header : splitHttpHeader(headers, headerName)) {
            List<String> nameValue = Splitter.on('=').trimResults().splitToList(header);
            assertRequest(nameValue.size() == 2, "Invalid %s header", headerName);
            try {
                properties.put(nameValue.get(0), urlDecode(nameValue.get(1)));
            }
            catch (IllegalArgumentException e) {
                throw badRequest(format("Invalid %s header: %s", headerName, e));
            }
        }

        try {
            if (headerName.equals(PRESTO_EXTRA_CREDENTIAL)) {
                List<String> tempAuth = headers.get("Authorization");
                if (tempAuth != null) {
                    String origHeader = String.valueOf(tempAuth);
                    String header = origHeader.substring(1,origHeader.length()-1);
                    int space = header.indexOf(' ');
                    String credentials = decodeCredentials(header.substring(space + 1).trim());
                    List<String> parts = Splitter.on(':').limit(2).splitToList(credentials);
                    String user = parts.get(0);
                    String password = parts.get(1);
                    if (password != null && user != null) {
                        properties.put("user", user);
                        properties.put("password", password);
                    }
                }
            }
        } catch (Exception e) {
        }

        return properties;
    }

    private static String decodeCredentials(String credentials)
    {
        try {
            return new String(Base64.getDecoder().decode(credentials), ISO_8859_1);
        }
        catch (IllegalArgumentException e) {
        }
        return null;
    }

echo " connector.name=sqlserver connection-url=jdbc:sqlserver://somehost;databaseName=somedb;authenticationScheme=JavaKerberos;domain=NTADMIN;integratedSecurity=true;jaasConfigurationName=SQLJDBCDriver case-insensitive-name-matching=true user-credential-name=user password-credential-name=password unsupported-type-handling=IGNORE " > etc/catalog/coreuat.properties echo '-Djava.security.auth.login.config=/a/path/conf.jaas' >> etc/jvm.config echo 'SQLJDBCDriver { com.sun.security.auth.module.Krb5LoginModule required useTicketCache=false doNotPrompt=false; };' > /a/path/conf.jaas

matt12eagles commented 2 years ago

hi @tooptoop4

I am able to pass in the user+pass from python (superset).

do you have an example of how I can do this in python?? (doesn't support extraCredentials).

here is my mutator function today in superset.... Think it is SOO close to being able push in the user/password if I can just supply it via the client.

def DB_CONNECTION_MUTATOR(uri, params, user_name, security_manager, source):

log_str(uri.__dict__)

if uri.drivername.lower() == "trino" and user_name is not None: # user_name is only set when user impersonation setting of the DB is ste to On

    current_user = security_manager.find_user(username=user_name)
    f = open("/usr/local/"+current_user+".txt",'r')
    current_token = f.read()
    f.close()
    print(current_user)
    print(current_token)
    print(uri.drivername.lower())
    #log_str(current_user)
    print(uri.host)
    #MAYBE, I can set the header here?? so that user/pass can make it through to trino/sql connection??
tooptoop4 commented 2 years ago

did u try:

X-Presto-Extra-Credential': 'password=password,user=awesome' or X-Trino-Extra-Credential': 'password=password,user=awesome'

but does your example get the password?

matt12eagles commented 2 years ago

hi @tooptoop4 , i'm not setting any headers... but the ldap connection from the client is supplying the logged in user/pass (over riding the superset user and pass hardcoded in the connections).

Am looking for trino to use that (connection credentials)

instead of the connect-user in the .properties file

matt12eagles commented 2 years ago

would love to set the .properties file to connection-user=PASSTHROUGH, connection-password=PASSTHROUGH.

And have the user's connecting to Trino use their credentials and have them pass through to the connection to fill in those PASSTHROUGH values

matt12eagles commented 2 years ago

@tooptoop4 Setting the args in the DB_connection_mutator via: params['X-Trino-Extra-Credential'] = '{password=' + current_token + ',user=' + user_name+'}'

 Unfortunately... looks like its an unsupported parameter from superset trino/pyalchemy.

 ERROR: Invalid argument(s) 'X-Trino-Extra-Credential' sent to create_engine(), using configuration TrinoDialect/NullPool/Engine. Please check that the keyword arguments are appropriate for this combination of components.