141 lines
3.4 KiB
Go
141 lines
3.4 KiB
Go
// Copyright 2015 ISRG. All rights reserved
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
package policy
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/letsencrypt/boulder/core"
|
|
blog "github.com/letsencrypt/boulder/log"
|
|
"github.com/letsencrypt/boulder/sa"
|
|
|
|
gorp "github.com/letsencrypt/boulder/Godeps/_workspace/src/gopkg.in/gorp.v1"
|
|
)
|
|
|
|
const whitelisted = "whitelist"
|
|
const blacklisted = "blacklist"
|
|
|
|
type domainRule struct {
|
|
Rule string `db:"rule"`
|
|
Type string `db:"type"`
|
|
}
|
|
|
|
// PolicyAuthorityDatabaseImpl enforces policy decisions based on various rule
|
|
// lists
|
|
type PolicyAuthorityDatabaseImpl struct {
|
|
log *blog.AuditLogger
|
|
dbMap *gorp.DbMap
|
|
}
|
|
|
|
// NewPolicyAuthorityDatabaseImpl constructs a Policy Authority Database (and
|
|
// creates tables if they are non-existent)
|
|
func NewPolicyAuthorityDatabaseImpl(driver, name string) (padb core.PolicyAuthorityDatabase, err error) {
|
|
logger := blog.GetAuditLogger()
|
|
dbMap, err := sa.NewDbMap(driver, name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dbMap.AddTableWithName(domainRule{}, "ruleList").SetKeys(false, "Rule")
|
|
|
|
err = dbMap.CreateTablesIfNotExists()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
padb = &PolicyAuthorityDatabaseImpl{
|
|
dbMap: dbMap,
|
|
log: logger,
|
|
}
|
|
|
|
return padb, nil
|
|
}
|
|
|
|
// AddRule will add a whitelist or blacklist rule to the database
|
|
func (padb *PolicyAuthorityDatabaseImpl) AddRule(rule string, rType string) error {
|
|
tx, err := padb.dbMap.Begin()
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
r := domainRule{
|
|
Rule: rule,
|
|
}
|
|
switch rType {
|
|
case blacklisted:
|
|
r.Type = "blacklist"
|
|
case whitelisted:
|
|
r.Type = "whitelist"
|
|
default:
|
|
return fmt.Errorf("Unsupported rule type: %s", rType)
|
|
}
|
|
err = tx.Insert(&r)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
|
|
err = tx.Commit()
|
|
return err
|
|
}
|
|
|
|
func (padb *PolicyAuthorityDatabaseImpl) DeleteRule(rule string) error {
|
|
obj, err := padb.dbMap.Get(&domainRule{}, rule)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
dbRule := obj.(domainRule)
|
|
_, err = padb.dbMap.Delete(dbRule)
|
|
return nil
|
|
}
|
|
|
|
func (padb *PolicyAuthorityDatabaseImpl) GetRules(typeFilter string) ([]string, error) {
|
|
var dR []domainRule
|
|
_, err := padb.dbMap.Select(&dR, "SELECT * FROM ruleList WHERE type = :rType", map[string]interface{}{"rType": typeFilter})
|
|
rules := []string{}
|
|
for _, rule := range dR {
|
|
rules = append(rules, rule.Rule)
|
|
}
|
|
return rules, err
|
|
}
|
|
|
|
// CheckRules will query the database for white/blacklist rules that match host,
|
|
// if both whitelist and blacklist rules are found the whitelist will always win
|
|
func (padb *PolicyAuthorityDatabaseImpl) CheckRules(host string, requireWhitelist bool) error {
|
|
var rules []domainRule
|
|
_, err := padb.dbMap.Select(
|
|
&rules,
|
|
`SELECT type,rule FROM ruleList WHERE :host LIKE rule`,
|
|
map[string]interface{}{"host": host},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var wRules []string
|
|
var bRules []string
|
|
for _, rule := range rules {
|
|
switch rule.Type {
|
|
case blacklisted:
|
|
bRules = append(bRules, rule.Rule)
|
|
case whitelisted:
|
|
wRules = append(wRules, rule.Rule)
|
|
}
|
|
}
|
|
|
|
if requireWhitelist && len(wRules) == 0 {
|
|
return fmt.Errorf("Domain name is not whitelisted for issuance")
|
|
} else if len(wRules)+len(bRules) > 0 {
|
|
padb.log.Info(fmt.Sprintf("Hostname [%s] matches rules, Whitelist: %s, Blacklist: %s", host, wRules, bRules))
|
|
if len(wRules) > 0 {
|
|
return nil
|
|
}
|
|
return BlacklistedError{}
|
|
}
|
|
|
|
return nil
|
|
}
|