package auth

import (
    "errors"
    "fmt"
    "log"
    "net/url"
    "regexp"
    "time"

    "github.com/nsqio/nsq/internal/http_api"
)

type Authorization struct {
    Topic       string   `json:"topic"`
    Channels    []string `json:"channels"`
    Permissions []string `json:"permissions"`
}

type State struct {
    TTL            int             `json:"ttl"`
    Authorizations []Authorization `json:"authorizations"`
    Identity       string          `json:"identity"`
    IdentityURL    string          `json:"identity_url"`
    Expires        time.Time
}

func (a *Authorization) HasPermission(permission string) bool {
    for _, p := range a.Permissions {
        if permission == p {
            return true
        }
    }
    return false
}

func (a *Authorization) IsAllowed(topic, channel string) bool {
    if channel != "" {
        if !a.HasPermission("subscribe") {
            return false
        }
    } else {
        if !a.HasPermission("publish") {
            return false
        }
    }

    topicRegex := regexp.MustCompile(a.Topic)

    if !topicRegex.MatchString(topic) {
        return false
    }

    for _, c := range a.Channels {
        channelRegex := regexp.MustCompile(c)
        if channelRegex.MatchString(channel) {
            return true
        }
    }
    return false
}

func (a *State) IsAllowed(topic, channel string) bool {
    for _, aa := range a.Authorizations {
        if aa.IsAllowed(topic, channel) {
            return true
        }
    }
    return false
}

func (a *State) IsExpired() bool {
    if a.Expires.Before(time.Now()) {
        return true
    }
    return false
}

func QueryAnyAuthd(authd []string, remoteIP, tlsEnabled, authSecret string,
    connectTimeout time.Duration, requestTimeout time.Duration) (*State, error) {
    for _, a := range authd {
        authState, err := QueryAuthd(a, remoteIP, tlsEnabled, authSecret, connectTimeout, requestTimeout)
        if err != nil {
            log.Printf("Error: failed auth against %s %s", a, err)
            continue
        }
        return authState, nil
    }
    return nil, errors.New("Unable to access auth server")
}

func QueryAuthd(authd, remoteIP, tlsEnabled, authSecret string,
    connectTimeout time.Duration, requestTimeout time.Duration) (*State, error) {
    v := url.Values{}
    v.Set("remote_ip", remoteIP)
    v.Set("tls", tlsEnabled)
    v.Set("secret", authSecret)

    endpoint := fmt.Sprintf("http://%s/auth?%s", authd, v.Encode())

    var authState State
    client := http_api.NewClient(nil, connectTimeout, requestTimeout)
    if err := client.GETV1(endpoint, &authState); err != nil {
        return nil, err
    }

    // validation on response
    for _, auth := range authState.Authorizations {
        for _, p := range auth.Permissions {
            switch p {
            case "subscribe", "publish":
            default:
                return nil, fmt.Errorf("unknown permission %s", p)
            }
        }

        if _, err := regexp.Compile(auth.Topic); err != nil {
            return nil, fmt.Errorf("unable to compile topic %q %s", auth.Topic, err)
        }

        for _, channel := range auth.Channels {
            if _, err := regexp.Compile(channel); err != nil {
                return nil, fmt.Errorf("unable to compile channel %q %s", channel, err)
            }
        }
    }

    if authState.TTL <= 0 {
        return nil, fmt.Errorf("invalid TTL %d (must be >0)", authState.TTL)
    }

    authState.Expires = time.Now().Add(time.Duration(authState.TTL) * time.Second)
    return &authState, nil
}

authorizations.go的更多相关文章

  1. WSO2 API Manager 替换mysql作为数据库,解决AuthorizationUtils Could not set authorizations for the root问题

    按照wso2官网(https://docs.wso2.com/display/ADMIN44x/Changing+to+MySQL)配置AM的数据库,想从H2换成Mysql5.7,费了将近一天的时间, ...

  2. (转载) RESTful API 设计指南

    作者: 阮一峰 日期: 2014年5月22日 网络应用程序,分为前端和后端两个部分.当前的发展趋势,就是前端设备层出不穷(手机.平板.桌面电脑.其他专用设备......). 因此,必须有一种统一的机制 ...

  3. 使用swagger作为restful api的doc文档生成

    初衷 记得以前写接口,写完后会整理一份API接口文档,而文档的格式如果没有具体要求的话,最终展示的文档则完全决定于开发者的心情.也许多点,也许少点.甚至,接口总是需要适应新需求的,修改了,增加了,这份 ...

  4. .NET WebAPI 用ActionFilterAttribute实现token令牌验证与对Action的权限控制

    项目背景是一个社区类的APP(求轻吐...),博主主要负责后台业务及接口.以前没玩过webAPI,但是领导要求必须用这个(具体原因鬼知道),只好硬着头皮上了. 最近刚做完权限这一块,分享出来给大家.欢 ...

  5. RESTful API 设计指南

    转自:http://www.ruanyifeng.com/blog/2014/05/restful_api.html 网络应用程序,分为前端和后端两个部分.当前的发展趋势,就是前端设备层出不穷(手机. ...

  6. RESTful API URI 设计的一些总结

    非常赞的四篇文章: Resource Naming Best Practices for Designing a Pragmatic RESTful API 撰写合格的 REST API JSON 风 ...

  7. PHP7函数大全(4553个函数)

    转载来自: http://www.infocool.net/kb/PHP/201607/168683.html a 函数 说明 abs 绝对值 acos 反余弦 acosh 反双曲余弦 addcsla ...

  8. CentOS搭建SVN记录

    1.安装subversion(client and server) $ yum install subversion $ yum install mod_dav_svn 安装成功之后使用 svnser ...

  9. geotrellis使用(五)使用scala操作Accumulo

    要想搞明白Geotrellis的数据处理情况,首先要弄清楚数据的存放,Geotrellis将数据存放在Accumulo中. Accumulo是一个分布式的Key Value型NOSQL数据库,官网为( ...

随机推荐

  1. 单片机PWM调制技术

    我们可以看看下图,下图就是一个典型的PWM的波形图. T是一个周期,T1就是高电平所占用的时间,T2就是低电平所占用的时间. 如上图所示T1为脉冲宽度(就是导通时间),周期为T,则输出电压的平均值为U ...

  2. Mac 电脑前端环境配置

    恍惚间,好久没有在外面写过随笔了.在阿里的那两年,学到了许多,也成长了许多,认识了很多可爱的人,也明白了很多社会的事.最后种种艰难抉择,我来到了美团成都,一个贫穷落后但更自由开放弹性的地方.已经误以为 ...

  3. MySql 动态语句

    MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) ...

  4. TabBarController和其他view无法建立Relationship segue的原因

    拖拽怎么也没有那个出现,最后看sourcecode发现是那个那个viewcrontroler的XML 元素不是TabBarController.在Sourcecode里面改了一下,解决了这个问题. 总 ...

  5. tomcat 绑定ipv4端口

    在<tomcat>/bin目录打开catalina.sh,然后添加如下内容: JAVA_OPTS="$JAVA_OPTS -Djava.net.preferIPv4Stack=t ...

  6. windows系统下输入法图标显示设置

    原先任务栏有两个搜狗输入法的标志,还有一个"中/英"的图标:甚至桌面还悬浮这一个搜狗输入法图标. 打开vscode等工具时,桌面悬浮的图标有时可能会遮挡到一些信息,十分不爽. 如今 ...

  7. js中window对象的opener属性的一个坑

    2018-05-08 17:48:33 今天我编写代码碰到了一个让我纠结了很久的坑,特别想在此说一下,让其他人避免我踏过的这个坑. 这个坑就是:在我自己写的子窗口中用opener属性却获取不到父窗口的 ...

  8. spring boot:thymeleaf使用详解

    简单说, Thymeleaf 是一个跟 Velocity.FreeMarker 类似的模板引擎,它可以完全替代 JSP .相较与其他的模板引擎,它有如下三个极吸引人的特点: 1.Thymeleaf 在 ...

  9. Java多线程:生命周期,实现与调度

    Java线程生命周期 Java线程实现方法 继承Thread类,重写run()方法 实现Runnable接口,便于继承其他类 Callable类替换Runnable类,实现返回值 Future接口对任 ...

  10. SSM博客

    最近在写基于SSM 的博客,用的是spring+springmvc+mybatis搭建的,用的maven+github管理项目,目前完成了登录注册以及用户管理员的增删改查,后续的功能还需要完善,如何建 ...