-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathtrouble.go
More file actions
129 lines (116 loc) · 3.6 KB
/
trouble.go
File metadata and controls
129 lines (116 loc) · 3.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package main
import (
"crypto/x509"
"encoding/json"
"fmt"
"html/template"
"net/http"
"time"
"github.com/dmwm/auth-proxy-server/cric"
"github.com/dmwm/cmsauth"
)
// Dummy check functions — replace with real logic
func isCMSVOMember(cert *x509.Certificate) bool {
// TODO: need proper check VO membership
return true
//return strings.Contains(cert.Subject.String(), "CMS")
}
func userDetails(cert *x509.Certificate) (cmsauth.CricEntry, error) {
dnParts := getDNParts(cert)
rec, err := cric.FindUser(dnParts)
if err != nil {
return rec, err
}
return rec, nil
}
func map2string(roles map[string][]string) string {
data, err := json.MarshalIndent(roles, "", " ")
if err != nil {
return fmt.Sprintf("%+v", roles)
}
return string(data)
}
var tmpl = template.Must(template.New("help").Parse(`
<!DOCTYPE html>
<html>
<head>
<title>CMSWEB authentication help</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link rel="stylesheet" type="text/css" media="screen" href="/css/cmsweb.css" />
</head>
<body>
<h2>Certificate authentication help</h2>
<p>Your browser offered valid DN '{{.DN}}'.</p>
<p>Your certificate is valid from {{.NotBefore}} to {{.NotAfter}}; {{.DaysRemaining}} days of validity remain.</p>
<p>Your certificate {{.Passed}} basic validation.</p>
<p>Your certificate is {{.CMSVOMember}}.</p>
<p>{{.Userdetails}}</p>
<p>For more details please see <a href="https://twiki.cern.ch/twiki/bin/view/CMS/DQMGUIGridCertificate">certificate setup instructions</a> for the most commonly needed steps.</p>
</body>
</html>
`))
func authTroubleHandler(w http.ResponseWriter, r *http.Request) {
if r.TLS == nil || len(r.TLS.PeerCertificates) == 0 {
http.Error(w, "No client certificate provided", http.StatusUnauthorized)
return
}
badCertificate := false
cert := r.TLS.PeerCertificates[0]
dn := cert.Subject.String()
notBefore := cert.NotBefore.UTC().Format("Jan 2 15:04:05 2006 GMT")
notAfter := cert.NotAfter.UTC().Format("Jan 2 15:04:05 2006 GMT")
daysRemaining := int(time.Until(cert.NotAfter).Hours() / 24)
// validation steps
cmsVOMember := "CMS VO member"
if !isCMSVOMember(cert) {
cmsVOMember = "not CMS VO member"
badCertificate = true
}
passed := "passed"
if daysRemaining < 0 {
passed = "not passed"
badCertificate = true
}
var details string
if rec, err := userDetails(cert); err == nil {
details = fmt.Sprintf("Your certificate is mapped to <br/><b>Name:</b> %s<br/><b>Login:</b> %s<br/><b>ID:</b> %v<br/><b>Roles:</b> %+v<br/><b>DNs:</b> %v<br/>in CRIC database",
rec.Name, rec.Login, rec.ID, map2string(rec.Roles), rec.DNs)
} else {
details = fmt.Sprintf("Provided certificate does not match with any record in CRIC database. ERROR: %v", err.Error())
badCertificate = true
}
data := struct {
DN string
NotBefore string
NotAfter string
DaysRemaining int
Userdetails template.HTML
Passed string
CMSVOMember string
}{
DN: dn,
NotBefore: notBefore,
NotAfter: notAfter,
DaysRemaining: daysRemaining,
Userdetails: template.HTML(details),
Passed: passed,
CMSVOMember: cmsVOMember,
}
if badCertificate {
w.WriteHeader(http.StatusUnauthorized)
}
// check if client asked for JSON
if r.Header.Get("Accept") == "application/json" {
if bytes, err := json.MarshalIndent(data, "", " "); err == nil {
w.Write(bytes)
} else {
w.Write([]byte(fmt.Sprintf("%v", data)))
}
return
}
err := tmpl.Execute(w, data)
if err != nil {
http.Error(w, "Internal template error", http.StatusInternalServerError)
}
}