Skip to content

Commit

Permalink
Update the example plugin to copy the template
Browse files Browse the repository at this point in the history
The example plugin should be a better copy of the template (eg use two files,
connector.go and plugin.go) so that it's clearer to people trying to build
plugins exactly how to create and build them in practice

This reorganizes the content to better mimic the templates and updates
the Dockerfile to correctly build the plugin.
  • Loading branch information
Geri Jennings committed Dec 30, 2019
1 parent 404bcdf commit 591dc87
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 110 deletions.
2 changes: 1 addition & 1 deletion test/plugin/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ COPY . .
RUN mkdir -p /usr/local/lib/secretless && \
go build -buildmode=plugin \
-o /usr/local/lib/secretless/example-plugin.so \
./example/example_plugin.go
./example/

# Do not remove this - we are intentionally trying to exercise
# limited user functionality
Expand Down
70 changes: 70 additions & 0 deletions test/plugin/example/connector.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package main

import (
"bufio"
"fmt"
"net"

"github.com/cyberark/secretless-broker/pkg/secretless/log"
"github.com/cyberark/secretless-broker/pkg/secretless/plugin/connector"
)

// SingleUseConnector creates an authenticated connection to a target TCP service.
type SingleUseConnector struct {
logger log.Logger
}

// Connect is the function that implements the tcp.Connector func signature in this
// example plugin. It has access to the client connection and the credentials (as a map),
// and is expected to return the target service connection.
//
// This example connector works as follows:
// 1. Waits for the initial message from the client
// 2. Connect to a target service whose address is the value of the credential identified
// by the key "address"
// 3. Inject credentials from a credential identified by the key "auth"
// 4. Write the initial message from the client with some modification
func (connector *SingleUseConnector) Connect(
clientConn net.Conn,
credentialValuesByID connector.CredentialValuesByID,
) (net.Conn, error) {

connector.logger.Debugln("Waiting for initial write from client")
clientInitMsg, _, err := bufio.NewReader(clientConn).ReadLine()
if err != nil {
return nil, err
}

connector.logger.Debugln("Dialing target service")
conn, err := net.Dial("tcp", string(credentialValuesByID["address"]))
if err != nil {
return nil, err
}

connector.logger.Debugln("Sending packet with injected credentials to target service")
credInjectionPacket := []byte(
fmt.Sprintf(
"credential injection: %s\n",
string(credentialValuesByID["auth"]),
),
)
_, err = conn.Write(credInjectionPacket)
if err != nil {
return nil, err
}

connector.logger.Debugln("Sending modified client initial packet to target service")
initMsgPacket := []byte(
fmt.Sprintf(
"initial message from client: %s\n",
string(clientInitMsg),
),
)
_, err = conn.Write(initMsgPacket)
if err != nil {
return nil, err
}

connector.logger.Debugln("Successfully connected to target service")
return conn, nil
}
109 changes: 0 additions & 109 deletions test/plugin/example/example_plugin.go

This file was deleted.

47 changes: 47 additions & 0 deletions test/plugin/example/plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package main

import (
"net"

"github.com/cyberark/secretless-broker/pkg/secretless/plugin/connector"
"github.com/cyberark/secretless-broker/pkg/secretless/plugin/connector/tcp"
)

// NewConnector is a required method on the tcp.Plugin interface. It returns a
// tcp.Connector.
//
// The single argument passed in is of type connector.Resources. It contains
// connector-specific config and a logger.
func NewConnector(conRes connector.Resources) tcp.Connector {
connectorFunc := func(
clientConn net.Conn,
credentialValuesByID connector.CredentialValuesByID,
) (backendConn net.Conn, err error) {
// singleUseConnector is responsible for generating the authenticated connection
// to the target service for each incoming client connection
singleUseConnector := &SingleUseConnector{
logger: conRes.Logger(),
}

return singleUseConnector.Connect(clientConn, credentialValuesByID)
}

return tcp.ConnectorFunc(connectorFunc)
}

// PluginInfo is required as part of the Secretless plugin spec. It provides
// important metadata about the plugin.
func PluginInfo() map[string]string {
return map[string]string{
"pluginAPIVersion": "0.1.0",
"type": "connector.tcp",
"id": "example-tcp-connector",
"description": "Example TCP Connector Plugin",
}
}

// GetTCPPlugin is required as part of the Secretless plugin spec for TCP connector
// plugins. It returns the TCP plugin.
func GetTCPPlugin() tcp.Plugin {
return tcp.ConnectorConstructor(NewConnector)
}

0 comments on commit 591dc87

Please sign in to comment.