99 "bytes"
1010 "context"
1111 "crypto/md5"
12+ "crypto/rand"
1213 "crypto/sha1"
1314 "crypto/sha256"
1415 "crypto/sha512"
@@ -22,6 +23,7 @@ import (
2223 "hash"
2324 "io"
2425 "log"
26+ "math/big"
2527 "net/http"
2628 "net/url"
2729 "os"
@@ -167,8 +169,10 @@ func New(u *url.URL, r *simulator.Registry) ([]string, http.Handler) {
167169 {internal .VCenterOVFLibraryItem + "/" , s .libraryItemOVFID },
168170 {internal .VCenterVMTXLibraryItem , s .libraryItemCreateTemplate },
169171 {internal .VCenterVMTXLibraryItem + "/" , s .libraryItemTemplateID },
172+ {"/vcenter/certificate-authority/" , s .certificateAuthority },
170173 {internal .DebugEcho , s .debugEcho },
171174 // /api/ patterns.
175+ {vapi .Path , s .jsonRPC },
172176 {internal .SecurityPoliciesPath , s .librarySecurityPolicies },
173177 {internal .TrustedCertificatesPath , s .libraryTrustedCertificates },
174178 {internal .TrustedCertificatesPath + "/" , s .libraryTrustedCertificatesID },
@@ -179,7 +183,10 @@ func New(u *url.URL, r *simulator.Registry) ([]string, http.Handler) {
179183 s .HandleFunc (h .p , h .m )
180184 }
181185
182- return []string {rest .Path + "/" , vapi .Path + "/" }, s
186+ return []string {
187+ rest .Path , rest .Path + "/" ,
188+ vapi .Path , vapi .Path + "/" ,
189+ }, s
183190}
184191
185192func (s * handler ) withClient (f func (context.Context , * vim25.Client ) error ) error {
@@ -266,8 +273,13 @@ func (s *handler) HandleFunc(pattern string, handler func(http.ResponseWriter, *
266273}
267274
268275func (s * handler ) isAuthorized (r * http.Request ) bool {
269- if r .Method == http .MethodPost && strings .HasSuffix (r .URL .Path , internal .SessionPath ) && s .action (r ) == "" {
270- return true
276+ if r .Method == http .MethodPost && s .action (r ) == "" {
277+ if r .URL .Path == vapi .Path {
278+ return true
279+ }
280+ if strings .HasSuffix (r .URL .Path , internal .SessionPath ) {
281+ return true
282+ }
271283 }
272284 id := r .Header .Get (internal .SessionCookieName )
273285 if id == "" {
@@ -565,6 +577,106 @@ func (s *handler) session(w http.ResponseWriter, r *http.Request) {
565577 }
566578}
567579
580+ // just enough json-rpc to support Supervisor upgrade testing
581+ func (s * handler ) jsonRPC (w http.ResponseWriter , r * http.Request ) {
582+ if r .Method != http .MethodPost {
583+ w .WriteHeader (http .StatusMethodNotAllowed )
584+ return
585+ }
586+
587+ var rpc , out map [string ]any
588+
589+ if Decode (r , w , & rpc ) {
590+ params := rpc ["params" ].(map [string ]any )
591+
592+ switch params ["serviceId" ] {
593+ case "com.vmware.cis.session" :
594+ switch params ["operationId" ] {
595+ case "create" :
596+ id := uuid .New ().String ()
597+ now := time .Now ()
598+ s .Session [id ] = & rest.Session {User : id , Created : now , LastAccessed : now }
599+ out = map [string ]any {"SECRET" : id }
600+ case "delete" :
601+ }
602+ }
603+
604+ res := map [string ]any {
605+ "jsonrpc" : rpc ["jsonrpc" ],
606+ "id" : rpc ["id" ],
607+ "result" : map [string ]any {
608+ "output" : out ,
609+ },
610+ }
611+
612+ StatusOK (w , res )
613+ }
614+ }
615+
616+ func (s * handler ) certificateAuthority (w http.ResponseWriter , r * http.Request ) {
617+ signer := s .Map .SessionManager ().TLS ().Certificates [0 ]
618+
619+ switch path .Base (r .URL .Path ) {
620+ case "get-root" :
621+ var encoded bytes.Buffer
622+ _ = pem .Encode (& encoded , & pem.Block {Type : "CERTIFICATE" , Bytes : signer .Leaf .Raw })
623+ OK (w , encoded .String ())
624+ case "sign-cert" :
625+ if r .Method != http .MethodPost {
626+ w .WriteHeader (http .StatusMethodNotAllowed )
627+ return
628+ }
629+
630+ var req struct {
631+ Duration string `json:"duration"`
632+ CSR string `json:"csr"`
633+ }
634+
635+ if Decode (r , w , & req ) {
636+ block , _ := pem .Decode ([]byte (req .CSR ))
637+ csr , err := x509 .ParseCertificateRequest (block .Bytes )
638+ if err != nil {
639+ BadRequest (w , err .Error ())
640+ return
641+ }
642+ duration , err := strconv .ParseInt (req .Duration , 10 , 64 )
643+ if err != nil {
644+ BadRequest (w , err .Error ())
645+ return
646+ }
647+
648+ serialNumber , _ := rand .Int (rand .Reader , new (big.Int ).Lsh (big .NewInt (1 ), 128 ))
649+ now := time .Now ()
650+ cert := & x509.Certificate {
651+ SerialNumber : serialNumber ,
652+ Subject : csr .Subject ,
653+ DNSNames : csr .DNSNames ,
654+ IPAddresses : csr .IPAddresses ,
655+ NotBefore : now ,
656+ NotAfter : now .Add (time .Hour * 24 * time .Duration (duration )),
657+ AuthorityKeyId : signer .Leaf .SubjectKeyId ,
658+ }
659+
660+ der , err := x509 .CreateCertificate (rand .Reader , cert , signer .Leaf , csr .PublicKey , signer .PrivateKey )
661+ if err != nil {
662+ BadRequest (w , err .Error ())
663+ return
664+ }
665+
666+ var encoded bytes.Buffer
667+ err = pem .Encode (& encoded , & pem.Block {Type : "CERTIFICATE" , Bytes : der })
668+ if err != nil {
669+ BadRequest (w , err .Error ())
670+ return
671+ }
672+
673+ OK (w , encoded .String ())
674+ }
675+ default :
676+ http .NotFound (w , r )
677+ }
678+ }
679+
568680func (s * handler ) action (r * http.Request ) string {
569681 return r .URL .Query ().Get ("~action" )
570682}
0 commit comments