001/* 002 * Copyright (c) 2023. The BifroMQ Authors. All Rights Reserved. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * Unless required by applicable law or agreed to in writing, 009 * software distributed under the License is distributed on an "AS IS" BASIS, 010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 011 * See the License for the specific language governing permissions and limitations under the License. 012 */ 013 014package com.baidu.bifromq.plugin.authprovider; 015 016 017import com.baidu.bifromq.plugin.authprovider.type.CheckResult; 018import com.baidu.bifromq.plugin.authprovider.type.Denied; 019import com.baidu.bifromq.plugin.authprovider.type.Error; 020import com.baidu.bifromq.plugin.authprovider.type.Failed; 021import com.baidu.bifromq.plugin.authprovider.type.Granted; 022import com.baidu.bifromq.plugin.authprovider.type.MQTT3AuthData; 023import com.baidu.bifromq.plugin.authprovider.type.MQTT3AuthResult; 024import com.baidu.bifromq.plugin.authprovider.type.MQTT5AuthData; 025import com.baidu.bifromq.plugin.authprovider.type.MQTT5AuthResult; 026import com.baidu.bifromq.plugin.authprovider.type.MQTT5ExtendedAuthData; 027import com.baidu.bifromq.plugin.authprovider.type.MQTT5ExtendedAuthResult; 028import com.baidu.bifromq.plugin.authprovider.type.MQTTAction; 029import com.baidu.bifromq.plugin.authprovider.type.Success; 030import com.baidu.bifromq.type.ClientInfo; 031import java.util.concurrent.CompletableFuture; 032import org.pf4j.ExtensionPoint; 033 034public interface IAuthProvider extends ExtensionPoint { 035 /** 036 * Implement this method to hook authentication logic of mqtt3 client into BifroMQ. 037 * 038 * @param authData the authentication data 039 */ 040 CompletableFuture<MQTT3AuthResult> auth(MQTT3AuthData authData); 041 042 /** 043 * Implement this method to hook authentication logic of mqtt5 client into BifroMQ. The default implementation will 044 * delegate to the auth method of mqtt3. 045 * 046 * @param authData the authentication data 047 * @return the authentication result 048 */ 049 default CompletableFuture<MQTT5AuthResult> auth(MQTT5AuthData authData) { 050 MQTT3AuthData.Builder mqtt3AuthDataBuilder = MQTT3AuthData.newBuilder(); 051 if (authData.hasCert()) { 052 mqtt3AuthDataBuilder.setCert(authData.getCert()); 053 } 054 if (authData.hasUsername()) { 055 mqtt3AuthDataBuilder.setUsername(authData.getUsername()); 056 } 057 if (authData.hasPassword()) { 058 mqtt3AuthDataBuilder.setPassword(authData.getPassword()); 059 } 060 if (authData.hasClientId()) { 061 mqtt3AuthDataBuilder.setClientId(authData.getClientId()); 062 } 063 mqtt3AuthDataBuilder.setRemoteAddr(authData.getRemoteAddr()); 064 mqtt3AuthDataBuilder.setRemotePort(authData.getRemotePort()); 065 mqtt3AuthDataBuilder.setClientId(authData.getClientId()); 066 return auth(mqtt3AuthDataBuilder.build()).thenApply(mqtt3AuthResult -> { 067 MQTT5AuthResult.Builder mqtt5AuthResultBuilder = MQTT5AuthResult.newBuilder(); 068 switch (mqtt3AuthResult.getTypeCase()) { 069 case OK -> { 070 mqtt5AuthResultBuilder.setSuccess(Success.newBuilder() 071 .setTenantId(mqtt3AuthResult.getOk().getTenantId()) 072 .setUserId(mqtt3AuthResult.getOk().getUserId()) 073 .putAllAttrs(mqtt3AuthResult.getOk().getAttrsMap()) 074 .build()); 075 } 076 case REJECT -> { 077 Failed.Builder failedBuilder = Failed.newBuilder(); 078 switch (mqtt3AuthResult.getReject().getCode()) { 079 case BadPass -> failedBuilder.setCode(Failed.Code.BadPass); 080 case NotAuthorized -> failedBuilder.setCode(Failed.Code.NotAuthorized); 081 case Error -> failedBuilder.setCode(Failed.Code.Error); 082 } 083 if (mqtt3AuthResult.getReject().hasReason()) { 084 failedBuilder.setReason(mqtt3AuthResult.getReject().getReason()); 085 } 086 mqtt5AuthResultBuilder.setFailed(failedBuilder.build()); 087 } 088 } 089 return mqtt5AuthResultBuilder.build(); 090 }); 091 } 092 093 /** 094 * Implement this method to hook extended authentication logic of mqtt5 client into BifroMQ. 095 * 096 * @param authData the extended authentication data 097 * @return the authentication result 098 */ 099 default CompletableFuture<MQTT5ExtendedAuthResult> extendedAuth(MQTT5ExtendedAuthData authData) { 100 return CompletableFuture.completedFuture(MQTT5ExtendedAuthResult.newBuilder() 101 .setFailed(Failed.newBuilder() 102 .setCode(Failed.Code.NotAuthorized) 103 .setReason("Not supported") 104 .build()) 105 .build()); 106 } 107 108 /** 109 * Implement this method to hook action permission check logic. 110 * 111 * @param client the client to check permission 112 * @param action the action 113 * @return true if the client is allowed to perform the action, false otherwise 114 */ 115 @Deprecated(since = "3.0") 116 CompletableFuture<Boolean> check(ClientInfo client, MQTTAction action); 117 118 /** 119 * Implement this method to hook action permission check logic. 120 * 121 * @param client the client to check permission 122 * @param action the action 123 * @return CheckResult 124 */ 125 default CompletableFuture<CheckResult> checkPermission(ClientInfo client, MQTTAction action) { 126 return check(client, action) 127 .handle((granted, e) -> { 128 if (e != null) { 129 return CheckResult.newBuilder() 130 .setError(Error.newBuilder() 131 .setReason(e.getMessage()) 132 .build()) 133 .build(); 134 } else if (granted) { 135 return CheckResult.newBuilder() 136 .setGranted(Granted.getDefaultInstance()) 137 .build(); 138 } else { 139 return CheckResult.newBuilder() 140 .setDenied(Denied.getDefaultInstance()) 141 .build(); 142 } 143 }); 144 } 145 146 /** 147 * This method will be called during broker shutdown 148 */ 149 default void close() { 150 } 151}