feat: add some Radius protocol code (#2351)

* feat: add radius server

* feat: parse org from packet

* feat: add comment

* Update main.go

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
This commit is contained in:
haiwu 2023-09-24 16:50:31 +08:00 committed by GitHub
parent f9cc6ed064
commit b94d06fb07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 176 additions and 0 deletions

View File

@ -20,6 +20,7 @@ staticBaseUrl = "https://cdn.casbin.org"
isDemoMode = false
batchSize = 100
ldapServerPort = 389
radiusServerPort = 1812
quota = {"organization": -1, "user": -1, "application": -1, "provider": -1}
logConfig = {"filename": "logs/casdoor.log", "maxdays":99999, "perm":"0770"}
initDataFile = "./init_data.json"

1
go.mod
View File

@ -66,6 +66,7 @@ require (
google.golang.org/api v0.138.0
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/square/go-jose.v2 v2.6.0
layeh.com/radius v0.0.0-20221205141417-e7fbddd11d68 // indirect
maunium.net/go/mautrix v0.16.0
modernc.org/sqlite v1.18.2
)

3
go.sum
View File

@ -1912,6 +1912,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@ -2768,6 +2769,8 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
layeh.com/radius v0.0.0-20221205141417-e7fbddd11d68 h1:2NDro2Jzkrqfngy/sA5GVnChs7fx8EzcQKFi/lI2cfg=
layeh.com/radius v0.0.0-20221205141417-e7fbddd11d68/go.mod h1:pFWM9De99EY9TPVyHIyA56QmoRViVck/x41WFkUlc9A=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=

View File

@ -25,6 +25,7 @@ import (
"github.com/casdoor/casdoor/ldap"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/proxy"
"github.com/casdoor/casdoor/radius"
"github.com/casdoor/casdoor/routers"
"github.com/casdoor/casdoor/util"
)
@ -81,6 +82,7 @@ func main() {
logs.SetLogFuncCall(false)
go ldap.StartLdapServer()
go radius.StartRadiusServer()
go object.ClearThroughputPerSecond()
beego.Run(fmt.Sprintf(":%v", port))

67
radius/server.go Normal file
View File

@ -0,0 +1,67 @@
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
//
// Licensed 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
//
// 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.
package radius
import (
"log"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/object"
"layeh.com/radius"
"layeh.com/radius/rfc2865"
)
// https://support.huawei.com/enterprise/zh/doc/EDOC1000178159/35071f9a#tab_3
func StartRadiusServer() {
server := radius.PacketServer{
Addr: "0.0.0.0:" + conf.GetConfigString("radiusServerPort"),
Handler: radius.HandlerFunc(handlerRadius),
SecretSource: radius.StaticSecretSource([]byte(`secret`)),
}
log.Printf("Starting Radius server on %s", server.Addr)
if err := server.ListenAndServe(); err != nil {
log.Fatalf("StartRadiusServer() failed, err = %v", err)
}
}
func handlerRadius(w radius.ResponseWriter, r *radius.Request) {
switch r.Code {
case radius.CodeAccessRequest:
handleAccessRequest(w, r)
default:
log.Printf("radius message, code = %d", r.Code)
}
}
func handleAccessRequest(w radius.ResponseWriter, r *radius.Request) {
username := rfc2865.UserName_GetString(r.Packet)
password := rfc2865.UserPassword_GetString(r.Packet)
organization := parseOrganization(r.Packet)
code := radius.CodeAccessAccept
log.Printf("username=%v, password=%v, code=%v, org=%v", username, password, code, organization)
if organization == "" {
code = radius.CodeAccessReject
w.Write(r.Response(code))
return
}
_, msg := object.CheckUserPassword(organization, username, password, "en")
if msg != "" {
code = radius.CodeAccessReject
w.Write(r.Response(code))
return
}
w.Write(r.Response(code))
}

62
radius/server_test.go Normal file
View File

@ -0,0 +1,62 @@
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
//
// Licensed 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
//
// 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.
//go:build !skipCi
// +build !skipCi
package radius
import (
"context"
"testing"
"layeh.com/radius"
"layeh.com/radius/rfc2865"
)
func TestAccessRequestRejected(t *testing.T) {
packet := radius.New(radius.CodeAccessRequest, []byte(`secret`))
rfc2865.UserName_SetString(packet, "admin")
rfc2865.UserPassword_SetString(packet, "12345")
vsa, err := radius.NewVendorSpecific(OrganizationVendorID, []byte("built-in"))
if err != nil {
t.Fatal(err)
}
packet.Add(rfc2865.VendorSpecific_Type, vsa)
response, err := radius.Exchange(context.Background(), packet, "localhost:1812")
if err != nil {
t.Fatal(err)
}
if response.Code != radius.CodeAccessReject {
t.Fatalf("Expected %v, got %v", radius.CodeAccessReject, response.Code)
}
}
func TestAccessRequestAccepted(t *testing.T) {
packet := radius.New(radius.CodeAccessRequest, []byte(`secret`))
rfc2865.UserName_SetString(packet, "admin")
rfc2865.UserPassword_SetString(packet, "123")
vsa, err := radius.NewVendorSpecific(OrganizationVendorID, []byte("built-in"))
if err != nil {
t.Fatal(err)
}
packet.Add(rfc2865.VendorSpecific_Type, vsa)
response, err := radius.Exchange(context.Background(), packet, "localhost:1812")
if err != nil {
t.Fatal(err)
}
if response.Code != radius.CodeAccessAccept {
t.Fatalf("Expected %v, got %v", radius.CodeAccessAccept, response.Code)
}
}

40
radius/util.go Normal file
View File

@ -0,0 +1,40 @@
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
//
// Licensed 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
//
// 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.
package radius
import (
"layeh.com/radius"
"layeh.com/radius/rfc2865"
)
const (
OrganizationVendorID = uint32(100)
)
func parseOrganization(p *radius.Packet) string {
for _, avp := range p.Attributes {
if avp.Type == rfc2865.VendorSpecific_Type {
attr := avp.Attribute
vendorId, value, err := radius.VendorSpecific(attr)
if err != nil {
return ""
}
if vendorId == OrganizationVendorID {
return string(value)
}
}
}
return ""
}