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

18
package org.apache.shardingsphere.proxy.frontend.mysql.auth;
T
tristaZero 已提交
19

ShardingSphere's avatar
ShardingSphere 已提交
20
import com.google.common.base.Strings;
T
tristaZero 已提交
21 22
import lombok.Getter;
import org.apache.commons.codec.digest.DigestUtils;
23
import org.apache.commons.collections4.CollectionUtils;
24 25
import org.apache.shardingsphere.db.protocol.mysql.constant.MySQLServerErrorCode;
import org.apache.shardingsphere.db.protocol.mysql.packet.handshake.MySQLAuthPluginData;
26 27
import org.apache.shardingsphere.infra.auth.ProxyUser;
import org.apache.shardingsphere.proxy.backend.schema.ProxySchemaContexts;
T
tristaZero 已提交
28 29

import java.util.Arrays;
30
import java.util.Collection;
31
import java.util.Map.Entry;
L
Liang Zhang 已提交
32
import java.util.Optional;
T
tristaZero 已提交
33 34

/**
35
 * Authentication handler for MySQL.
T
tristaZero 已提交
36 37
 */
@Getter
T
tuohai666 已提交
38
public final class MySQLAuthenticationHandler {
T
tristaZero 已提交
39
    
40
    private static final ProxySchemaContexts PROXY_SCHEMA_CONTEXTS = ProxySchemaContexts.getInstance();
41
    
42
    private final MySQLAuthPluginData authPluginData = new MySQLAuthPluginData();
T
tristaZero 已提交
43 44
    
    /**
45
     * Login.
T
tristaZero 已提交
46
     *
47
     * @param username username.
48 49
     * @param authResponse auth response
     * @param database database
50
     * @return login success or failure
T
tristaZero 已提交
51
     */
52 53
    public Optional<MySQLServerErrorCode> login(final String username, final byte[] authResponse, final String database) {
        Optional<ProxyUser> user = getUser(username);
54
        if (!user.isPresent() || !isPasswordRight(user.get().getPassword(), authResponse)) {
55 56
            return Optional.of(MySQLServerErrorCode.ER_ACCESS_DENIED_ERROR);
        }
57
        if (!isAuthorizedSchema(user.get().getAuthorizedSchemas(), database)) {
58 59
            return Optional.of(MySQLServerErrorCode.ER_DBACCESS_DENIED_ERROR);
        }
L
Liang Zhang 已提交
60
        return Optional.empty();
61
    }
62 63
    
    private Optional<ProxyUser> getUser(final String username) {
64
        for (Entry<String, ProxyUser> entry : PROXY_SCHEMA_CONTEXTS.getSchemaContexts().getAuthentication().getUsers().entrySet()) {
65 66 67
            if (entry.getKey().equals(username)) {
                return Optional.of(entry.getValue());
            }
68
        }
L
Liang Zhang 已提交
69
        return Optional.empty();
T
tristaZero 已提交
70 71
    }
    
72 73 74 75 76 77 78 79
    private boolean isPasswordRight(final String password, final byte[] authResponse) {
        return Strings.isNullOrEmpty(password) || Arrays.equals(getAuthCipherBytes(password), authResponse);
    }
    
    private boolean isAuthorizedSchema(final Collection<String> authorizedSchemas, final String schema) {
        return Strings.isNullOrEmpty(schema) || CollectionUtils.isEmpty(authorizedSchemas) || authorizedSchemas.contains(schema);
    }
    
T
tristaZero 已提交
80 81 82
    private byte[] getAuthCipherBytes(final String password) {
        byte[] sha1Password = DigestUtils.sha1(password);
        byte[] doubleSha1Password = DigestUtils.sha1(sha1Password);
83 84 85
        byte[] concatBytes = new byte[authPluginData.getAuthPluginData().length + doubleSha1Password.length];
        System.arraycopy(authPluginData.getAuthPluginData(), 0, concatBytes, 0, authPluginData.getAuthPluginData().length);
        System.arraycopy(doubleSha1Password, 0, concatBytes, authPluginData.getAuthPluginData().length, doubleSha1Password.length);
T
tristaZero 已提交
86 87 88 89 90
        byte[] sha1ConcatBytes = DigestUtils.sha1(concatBytes);
        return xor(sha1Password, sha1ConcatBytes);
    }
    
    private byte[] xor(final byte[] input, final byte[] secret) {
L
Liang Zhang 已提交
91
        byte[] result = new byte[input.length];
T
tristaZero 已提交
92 93 94 95 96 97
        for (int i = 0; i < input.length; ++i) {
            result[i] = (byte) (input[i] ^ secret[i]);
        }
        return result;
    }
}