Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into fix/refresh
Browse files Browse the repository at this point in the history
  • Loading branch information
chatiti committed Aug 2, 2024
2 parents 22998c9 + dc05abe commit 14ec6ad
Show file tree
Hide file tree
Showing 18 changed files with 804 additions and 217 deletions.
29 changes: 15 additions & 14 deletions controllers/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"strings"

"github.com/casbin/caswaf/object"
"github.com/casbin/caswaf/service"
"github.com/casbin/caswaf/util"
"github.com/hsluoyz/modsecurity-go/seclang/parser"
)
Expand All @@ -30,8 +29,12 @@ func (c *ApiController) GetRules() {
if c.RequireSignedIn() {
return
}
owner := c.Input().Get("owner")
if owner == "admin" {
owner = ""
}

rules, err := object.GetRules()
rules, err := object.GetRules(owner)
if err != nil {
c.ResponseError(err.Error())
return
Expand Down Expand Up @@ -76,7 +79,6 @@ func (c *ApiController) AddRule() {
return
}
c.Data["json"] = wrapActionResponse(object.AddRule(&rule))
go service.UpdateWAF()
c.ServeJSON()
}

Expand All @@ -100,7 +102,6 @@ func (c *ApiController) UpdateRule() {

id := c.Input().Get("id")
c.Data["json"] = wrapActionResponse(object.UpdateRule(id, &rule))
go service.UpdateWAF()
c.ServeJSON()
}

Expand All @@ -117,25 +118,24 @@ func (c *ApiController) DeleteRule() {
}

c.Data["json"] = wrapActionResponse(object.DeleteRule(&rule))
go service.UpdateWAF()
c.ServeJSON()
}

func checkExpressions(expressions []object.Expression, ruleType string) error {
func checkExpressions(expressions []*object.Expression, ruleType string) error {
values := make([]string, len(expressions))
for i, expression := range expressions {
values[i] = expression.Value
}
switch ruleType {
case "waf":
return checkWAFRule(values)
case "ip":
return checkIPRule(values)
case "WAF":
return checkWafRule(values)
case "IP":
return checkIpRule(values)
}
return nil
}

func checkWAFRule(rules []string) error {
func checkWafRule(rules []string) error {
for _, rule := range rules {
scanner := parser.NewSecLangScannerFromString(rule)
_, err := scanner.AllDirective()
Expand All @@ -146,10 +146,11 @@ func checkWAFRule(rules []string) error {
return nil
}

func checkIPRule(ipLists []string) error {
func checkIpRule(ipLists []string) error {
for _, ipList := range ipLists {
for _, ip := range strings.Split(ipList, " ") {
if net.ParseIP(ip) == nil {
for _, ip := range strings.Split(ipList, ",") {
_, _, err := net.ParseCIDR(ip)
if net.ParseIP(ip) == nil && err != nil {
return errors.New("Invalid IP address: " + ip)
}
}
Expand Down
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func main() {
casdoor.InitCasdoorConfig()
proxy.InitHttpClient()
object.InitSiteMap()
object.InitRuleMap()
run.InitAppMap()
run.InitSelfStart()
object.StartMonitorSitesLoop()
Expand Down
59 changes: 33 additions & 26 deletions object/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
package object

import (
"fmt"

"github.com/casbin/caswaf/util"
"github.com/xorm-io/core"
)
Expand All @@ -26,20 +28,29 @@ type Expression struct {
}

type Rule struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
Type string `xorm:"varchar(100) notnull" json:"type"`
Expressions []Expression `xorm:"mediumtext" json:"expressions"`
CreatedTime string `xorm:"varchar(100) notnull" json:"createdTime"`
UpdatedTime string `xorm:"varchar(100) notnull" json:"updatedTime"`
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100) notnull" json:"createdTime"`
UpdatedTime string `xorm:"varchar(100) notnull" json:"updatedTime"`

Type string `xorm:"varchar(100) notnull" json:"type"`
Expressions []*Expression `xorm:"mediumtext" json:"expressions"`
Action string `xorm:"varchar(100) notnull" json:"action"`
Reason string `xorm:"varchar(100) notnull" json:"reason"`
}

func GetRules() ([]*Rule, error) {
func GetGlobalRules() ([]*Rule, error) {
rules := []*Rule{}
err := ormer.Engine.Asc("owner").Desc("created_time").Find(&rules)
return rules, err
}

func GetRules(owner string) ([]*Rule, error) {
rules := []*Rule{}
err := ormer.Engine.Desc("updated_time").Find(&rules, &Rule{Owner: owner})
return rules, err
}

func getRule(owner string, name string) (*Rule, error) {
rule := Rule{Owner: owner, Name: name}
existed, err := ormer.Engine.Get(&rule)
Expand Down Expand Up @@ -70,15 +81,25 @@ func UpdateRule(id string, rule *Rule) (bool, error) {
if err != nil {
return false, err
}
err = refreshRuleMap()
if err != nil {
return false, err
}
return true, nil
}

func AddRule(rule *Rule) (bool, error) {
if _, err := ormer.Engine.Insert(rule); err != nil {
affected, err := ormer.Engine.Insert(rule)
if err != nil {
return false, err
} else {
return true, nil
}
if affected != 0 {
err = refreshRuleMap()
if err != nil {
return false, err
}
}
return affected != 0, nil
}

func DeleteRule(rule *Rule) (bool, error) {
Expand All @@ -90,20 +111,6 @@ func DeleteRule(rule *Rule) (bool, error) {
return affected != 0, nil
}

func GetWAFRules() string {
// Get all rules of type "waf".
rules := []*Rule{}
err := ormer.Engine.Where("type = ?", "waf").Find(&rules)
if err != nil {
return ""
}

res := ""
// get all expressions from rules
for _, rule := range rules {
for _, expression := range rule.Expressions {
res += expression.Value + "\n"
}
}
return res
func (rule *Rule) GetId() string {
return fmt.Sprintf("%s/%s", rule.Owner, rule.Name)
}
53 changes: 53 additions & 0 deletions object/rule_cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2023 The casbin 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 object

import (
"github.com/casbin/caswaf/util"
)

var ruleMap = map[string]*Rule{}

func InitRuleMap() {
err := refreshRuleMap()
if err != nil {
panic(err)
}
}

func refreshRuleMap() error {
newRuleMap := map[string]*Rule{}
rules, err := GetGlobalRules()
if err != nil {
return err
}

for _, rule := range rules {
newRuleMap[util.GetIdFromOwnerAndName(rule.Owner, rule.Name)] = rule
}

ruleMap = newRuleMap
return nil
}

func GetRulesByRuleIds(ids []string) []*Rule {
var res []*Rule
for _, id := range ids {
if rule, ok := ruleMap[id]; ok {
res = append(res, rule)
}
}
return res
}
35 changes: 17 additions & 18 deletions object/site.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"github.com/casbin/caswaf/run"
"github.com/casbin/caswaf/util"
"github.com/casdoor/casdoor-go-sdk/casdoorsdk"
"github.com/corazawaf/coraza/v3"
"github.com/xorm-io/core"
)

Expand All @@ -44,23 +43,23 @@ type Site struct {
UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`

Tag string `xorm:"varchar(100)" json:"tag"`
Domain string `xorm:"varchar(100)" json:"domain"`
OtherDomains []string `xorm:"varchar(500)" json:"otherDomains"`
NeedRedirect bool `json:"needRedirect"`
EnableWaf bool `json:"enableWaf"`
Waf coraza.WAF `xorm:"-" json:"-"`
Challenges []string `xorm:"mediumtext" json:"challenges"`
Host string `xorm:"varchar(100)" json:"host"`
Port int `json:"port"`
Hosts []string `xorm:"varchar(1000)" json:"hosts"`
SslMode string `xorm:"varchar(100)" json:"sslMode"`
SslCert string `xorm:"-" json:"sslCert"`
PublicIp string `xorm:"varchar(100)" json:"publicIp"`
Node string `xorm:"varchar(100)" json:"node"`
IsSelf bool `json:"isSelf"`
Status string `xorm:"varchar(100)" json:"status"`
Nodes []*Node `xorm:"mediumtext" json:"nodes"`
Tag string `xorm:"varchar(100)" json:"tag"`
Domain string `xorm:"varchar(100)" json:"domain"`
OtherDomains []string `xorm:"varchar(500)" json:"otherDomains"`
NeedRedirect bool `json:"needRedirect"`
EnableWaf bool `json:"enableWaf"`
Rules []string `xorm:"varchar(500)" json:"wafRuleIds"`
Challenges []string `xorm:"mediumtext" json:"challenges"`
Host string `xorm:"varchar(100)" json:"host"`
Port int `json:"port"`
Hosts []string `xorm:"varchar(1000)" json:"hosts"`
SslMode string `xorm:"varchar(100)" json:"sslMode"`
SslCert string `xorm:"-" json:"sslCert"`
PublicIp string `xorm:"varchar(100)" json:"publicIp"`
Node string `xorm:"varchar(100)" json:"node"`
IsSelf bool `json:"isSelf"`
Status string `xorm:"varchar(100)" json:"status"`
Nodes []*Node `xorm:"mediumtext" json:"nodes"`

CasdoorApplication string `xorm:"varchar(100)" json:"casdoorApplication"`
ApplicationObj *casdoorsdk.Application `xorm:"-" json:"applicationObj"`
Expand Down
65 changes: 65 additions & 0 deletions rule/rule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2024 The casbin 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 rule

import (
"fmt"
"net/http"

"github.com/casbin/caswaf/object"
)

type Rule interface {
checkRule(expressions []*object.Expression, req *http.Request) (bool, string, string, error)
}

func CheckRules(wafRuleIds []string, r *http.Request) (string, string, error) {
rules := object.GetRulesByRuleIds(wafRuleIds)
for _, rule := range rules {
var ruleObj Rule
switch rule.Type {
case "User-Agent":
ruleObj = &UaRule{}
case "IP":
ruleObj = &IpRule{}
case "WAF":
ruleObj = &WafRule{}
default:
return "", "", fmt.Errorf("unknown rule type: %s for rule: %s", rule.Type, rule.GetId())
}

isHit, action, reason, err := ruleObj.checkRule(rule.Expressions, r)
if err != nil {
return "", "", err
}
if action == "" {
action = rule.Action
}
if isHit {
if action == "Block" || action == "Drop" {
if rule.Reason != "" {
reason = rule.Reason
}
return action, reason, nil
} else if action == "Allow" {
return action, reason, nil
} else {
return "", "", fmt.Errorf("unknown rule action: %s for rule: %s", action, rule.GetId())
}
}
}

return "", "", nil
}
Loading

0 comments on commit 14ec6ad

Please sign in to comment.