mindxdl--common--web_cert_utils.go
// Copyright (c) 2021. Huawei Technologies Co., Ltd. All rights reserved.
// Package common this file define WebCertUtil
package common
import (
"crypto/tls"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"github.com/gin-gonic/gin"
"huawei.com/npu-exporter/hwlog"
"huawei.com/npu-exporter/limiter"
"huawei.com/npu-exporter/utils"
"io/ioutil"
"net/http"
"strconv"
"strings"
"time"
)
const keyLength = 4096
var webCert *WebCertUtil
// WebCertUtil WebCertUtil
type WebCertUtil struct {
*CertificateUtils
}
// NewWebCertUtil NewWebCertUtil
func NewWebCertUtil(dnsName, dirName string, overdueTime int) *WebCertUtil {
ws := &WebCertUtil{
CertificateUtils: NewCertificateUtils(dnsName, dirName, overdueTime),
}
if err := utils.MakeSureDir(ws.KeyStore); err != nil {
hwlog.RunLog.Fatal(err)
}
return ws
}
// GetWebCertUtil return webCert
func GetWebCertUtil() *WebCertUtil {
return webCert
}
// CheckCertValidityPeriod CheckCertValidityPeriod
func (ws *WebCertUtil) CheckCertValidityPeriod(interval time.Duration) {
hwlog.RunLog.Info("start cert period check...")
ticker := time.NewTicker(interval)
defer ticker.Stop()
hasTask := false
for {
_, ok := <-ticker.C
if !ok {
return
}
if hasTask {
continue
}
ws.Lock.RLock()
if ws.Cert == nil {
ws.Lock.RUnlock()
continue
}
x509Cert, err := x509.ParseCertificate(ws.Cert.Certificate[0])
if err != nil {
ws.Lock.RUnlock()
continue
}
err = utils.CheckValidityPeriodWithError(x509Cert, ws.OverdueTime)
ws.Lock.RUnlock()
if err == nil {
continue
}
hwlog.RunLog.Warn(err)
go func() {
hasTask = true
defer func() {
hasTask = false
hwlog.RunLog.Info("apply for a new certificate success")
}()
hwlog.RunLog.Info("apply for a new certificate because the certificate has expired")
if err = ws.ApplyForCertificateByRequest(); err != nil {
hwlog.RunLog.Error(err)
}
}()
}
}
// GetCaByRequest get ca by request
func (ws *WebCertUtil) GetCaByRequest() ([]byte, error) {
caByte, err := DefaultClsMgrClient.GetRootCertificate()
if err != nil {
return nil, err
}
hwlog.RunLog.Info("succeeded in getting ca certificate by request")
if err = ioutil.WriteFile(ws.CaStore, caByte, utils.RWMode); err != nil {
return nil, errors.New("write caBytes to file failed")
}
hwlog.RunLog.Info("succeeded in saving ca certificate to file")
ws.CaBytes = caByte
return caByte, nil
}
// ApplyForCertificateByRequest apply for certificate by request
func (ws *WebCertUtil) ApplyForCertificateByRequest() error {
certPem, err := DefaultClsMgrClient.ApplyForCertificatePemByte(ws.DNSName, ws.CaBytes, ws.PrivateKey)
if err != nil {
return err
}
hwlog.RunLog.Info("succeeded in getting certificate by request")
derStream := x509.MarshalPKCS1PrivateKey(ws.PrivateKey)
block := &pem.Block{
Type: RSAPrivateKey,
Bytes: derStream,
}
keyPem := pem.EncodeToMemory(block)
tlsCert, err := utils.ValidateCertPair(certPem, keyPem, false, ws.OverdueTime)
if err != nil {
return err
}
if err = ioutil.WriteFile(ws.CertStore, certPem, utils.RWMode); err != nil {
return errors.New("write certBytes to file failed ")
}
hwlog.RunLog.Info("succeeded in saving certificate to file")
ws.Lock.RLock()
defer ws.Lock.RUnlock()
ws.refreshCertStatus(tlsCert)
ws.Cert = tlsCert
return nil
}
func (ws *WebCertUtil) refreshCertStatus(tlsCert *tls.Certificate) {
// clear cert status record
ws.ClearCertificateMap()
caCert, err := utils.LoadCertsFromPEM(ws.CaBytes)
if err == nil {
// refresh ca record
err = utils.AddToCertStatusTrace(caCert)
}
if err != nil {
hwlog.RunLog.Error("prepare refresh ca info failed: " + err.Error())
}
x509Cert, err := x509.ParseCertificate(tlsCert.Certificate[0])
if err == nil {
// refresh certificate record
err = utils.AddToCertStatusTrace(x509Cert)
}
if err != nil {
hwlog.RunLog.Error("prepare refresh certificate info failed: " + err.Error())
}
hwlog.RunLog.Info("succeeded in refresh ca/cert info")
}
// SetHTTPSServer set http server config for one or two way auth
func (ws *WebCertUtil) SetHTTPSServer(s *http.Server, concurrency, maxConcurrency int,
cipherSuites []uint16, ginObj *gin.Engine) error {
tlsConfig, err := utils.NewTLSConfigV2(ws.CaBytes, *ws.Cert, cipherSuites)
if err != nil {
return err
}
tlsConfig.Certificates = nil
tlsConfig.GetCertificate = ws.GetCertificateFunc()
s.Handler = limiter.NewLimitHandler(concurrency, maxConcurrency, utils.Interceptor(ginObj, ws.CrlList), false)
s.TLSConfig = tlsConfig
return nil
}
// ReApplyCertificate reapply certificate
func (ws *WebCertUtil) ReApplyCertificate(algorithm int) error {
hwlog.RunLog.Info("prepare to reapply a new certificate")
if ws.PrivateKey == nil {
if _, err := ws.GenerateRSAPrivateKey(keyLength, algorithm); err != nil {
return err
}
}
if err := ws.ApplyForCertificateByRequest(); err != nil {
return err
}
return nil
}
// GetRequestClient get http client for request
func (ws *WebCertUtil) GetRequestClient(authMode string) (*http.Client, error) {
// https auth two way
if authMode == TwoWay {
requestClient, err := ws.GetTwoWayAuthRequestClient()
if err != nil {
return nil, err
}
return requestClient, nil
}
// https auth one way
pool, err := x509.SystemCertPool()
if err != nil {
return nil, fmt.Errorf("cannot get system trusted certificates pool: %w", err)
}
if !pool.AppendCertsFromPEM(ws.CaBytes) {
return nil, fmt.Errorf("failed to append to certificates pool")
}
c := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: pool,
},
},
}
return c, nil
}
// InitCert init cert and ca
func InitCert(sp *ServerParam) error {
ws := NewWebCertUtil(sp.DNSName, sp.DirName, sp.OverdueTime)
var reApply bool
var caBytes []byte
// load ca
_, err := ws.LoadCAOnStart(sp.AuthMode)
if err != nil && strings.Contains(err.Error(), ReApply) {
reApply = true
}
// reapply ca
if reApply {
caBytes, err = ws.GetCaByRequest()
if len(caBytes) == 0 || err != nil {
return err
}
reApply = false
}
if err != nil {
return err
}
// load cert and private key
_, err = ws.LoadCertAndKeyOnStart(sp.EncryptAlgorithm)
if err != nil && strings.Contains(err.Error(), ReApply) {
reApply = true
}
// reapply cert
if reApply {
if err = ws.ReApplyCertificate(sp.EncryptAlgorithm); err != nil {
return err
}
}
if err != nil {
return err
}
// init global WebCertUtil
webCert = ws
return nil
}
// StartServerListen StartServerListen
func StartServerListen(sp *ServerParam, engine *gin.Engine) {
s := &http.Server{
ReadTimeout: sp.ReadTimeOut * time.Second,
WriteTimeout: sp.WriteTimeOut * time.Second,
Addr: sp.IP + ":" + strconv.Itoa(sp.Port),
Handler: limiter.NewLimitHandler(sp.Concurrency, sp.MaxConcurrency, engine, false),
}
// http
if sp.EnableHTTP {
// http
hwlog.RunLog.Warn("Service started with an insecure http server enabled")
if err := s.ListenAndServe(); err != nil {
hwlog.RunLog.Error("Http server error and stopped")
}
return
}
// init web cert util
err := InitCert(sp)
if err != nil {
hwlog.RunLog.Error(err)
return
}
ParseTLSParams(sp)
wc := GetWebCertUtil()
if err = wc.SetHTTPSServer(s, sp.Concurrency, sp.MaxConcurrency, sp.CipherSuites,
engine); err != nil {
hwlog.RunLog.Error(err)
return
}
hwlog.RunLog.Info("start https server now...")
// start certificate period check
go wc.CheckCertValidityPeriod(sp.CheckCertPeriod)
if err = s.ListenAndServeTLS("", ""); err != nil {
hwlog.RunLog.Error("Https server error by: %s and stopped", err.Error())
}
}
mindxdl--common--web_cert_utils.go的更多相关文章
- Socket聊天程序——Common
写在前面: 上一篇记录了Socket聊天程序的客户端设计,为了记录的完整性,这里还是将Socket聊天的最后一个模块--Common模块记录一下.Common的设计如下: 功能说明: Common模块 ...
- angularjs 1 开发简单案例(包含common.js,service.js,controller.js,page)
common.js var app = angular.module('app', ['ngFileUpload']) .factory('SV_Common', function ($http) { ...
- Common Bugs in C Programming
There are some Common Bugs in C Programming. Most of the contents are directly from or modified from ...
- ANSI Common Lisp Practice - My Answers - Chatper - 3
Ok, Go ahead. 1 (a) (b) (c) (d) 2 注:union 在 Common Lisp 中的作用就是求两个集合的并集.但是这有一个前提,即给的两个列表已经满足集合的属性了.具体 ...
- [LeetCode] Lowest Common Ancestor of a Binary Tree 二叉树的最小共同父节点
Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. According ...
- [LeetCode] Lowest Common Ancestor of a Binary Search Tree 二叉搜索树的最小共同父节点
Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BS ...
- [LeetCode] Longest Common Prefix 最长共同前缀
Write a function to find the longest common prefix string amongst an array of strings. 这道题让我们求一系列字符串 ...
- 48. 二叉树两结点的最低共同父结点(3种变种情况)[Get lowest common ancestor of binary tree]
[题目] 输入二叉树中的两个结点,输出这两个结点在数中最低的共同父结点. 二叉树的结点定义如下: C++ Code 123456 struct BinaryTreeNode { int ...
- 动态规划求最长公共子序列(Longest Common Subsequence, LCS)
1. 问题描述 子串应该比较好理解,至于什么是子序列,这里给出一个例子:有两个母串 cnblogs belong 比如序列bo, bg, lg在母串cnblogs与belong中都出现过并且出现顺序与 ...
- 【leetcode】Longest Common Prefix
题目简述: Write a function to find the longest common prefix string amongst an array of strings. 解题思路: c ...
随机推荐
- 【长文详解】TypeScript、Babel、webpack以及IDE对TS的类型检查
只要接触过ts的前端同学都能回答出ts是js超集,它具备静态类型分析,能够根据类型在静态代码的解析过程中对ts代码进行类型检查,从而在保证类型的一致性.那,现在让你对你的webpack项目(其实任意类 ...
- 【SQLServer】max worker threads参数说明
本文介绍如何使用SQL Server Management Studio或Transact-SQL在SQL Server中配置最大工作线程服务器配置选项. max worker threads选项配置 ...
- vivo 全球商城:电商平台通用取货码设计
vivo官网商城开发团队 - Zhou Longjian 一.背景 随着O2O线上线下业务的不断扩展,电商平台也在逐步完善交易侧相关的产品功能.在最近的需求版本中,业务方为进一步提升用户的使用体验,规 ...
- 论文解读(RvNN)《Rumor Detection on Twitter with Tree-structured Recursive Neural Networks》
论文信息 论文标题:Rumor Detection on Twitter with Tree-structured Recursive Neural Networks论文作者:Jing Ma, Wei ...
- 阿里云SLB的http强制转https
公司的要求:要求强制http转https 我的环境是: 域名<--->slb的ip<-->源服务器nginx 具体做法是: 第一步:证书放到slb的https上,通过443端口 ...
- 自定义mapping与常见参数
PUT test { "mappings": { "dynamic": true, "properties": { "firstn ...
- 【前端必会】eslint搞起
介绍 eslint进行代码审查,统一代码风格,预防潜在BUG 官网 https://eslint.bootcss.com/docs/user-guide/getting-started 安装 init ...
- Oracle基础知识汇总一
Oracle基础知识 以下内容为本人的学习笔记,如需要转载,请声明原文链接 https://www.cnblogs.com/lyh1024/p/16720759.html oracle工具: SQ ...
- 智能工厂的ERP和MES之间的区别?
无论在哪里,ERP(Enterprise Resource Planning,企业资源计划)和MES(Manufacturing Execution System,即制造执行系统)系统都不是同样的东西 ...
- LeetCode - 数组的旋转总结
1. 数组的旋转总结 数组的旋转指的是将数组的最后若干个数提前到数组前面,数组的翻转指的是将数组的顺序颠倒.旋转可以通过多次翻转实现. 数组的翻转很简单,通过双指针来实现:交换数组的第一个数和最后一个 ...