goconnect

package module
v0.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 1, 2019 License: Apache-2.0 Imports: 19 Imported by: 3

README

GoConnect - a library for Telenor Connect ID

GoDoc Build Status Go Report Card codecov

This library makes it easy to integrate your Go (web) service with the Telenor Connect ID authorization and authentication service. To install it simply do a:

go get github.com/telenordigital/goconnect

Where's the demo?

Clone (or fork) the https://github.com/telenordigital/goconnect-sample/ repository to get a working demo with a development client included.

If you are impatient and you want to just run the demo quickly just cut and paste the following commands to fetch the demo compile it and run it:

go get github.com/telenordigital/goconnect-sample
cd $GOPATH/src/github.com/telenordigital/goconnect-sample
go build
./goconnect-sample

Then point your browser at http://localhost:8080/

Getting your own CONNECT ID client config

You can get your own CONNECT client configuration by going to the https://docs.telenordigital.com/ site and filling out the form there. Processing takes a business day or two. In the meanwhile you can use the client configuration included in this sample.

About the redirect URI parameters

The redirect URI parameters that you use when logging in must be configured both on the client side (ie your service) and on the server side (ie on the Telenor CONNECT ID servers). The service will only accept the configured redirect URI parameters to be used so you can't use custom redirects for each deployment you have.

Using the same Connect ID client config for different deployments

You probably want to several different client types - one for your testing environment, one for development and one for your production environment.

You can configure multiple redirect URLs for each client so in theory you could use the same client configuration for all of your environments but it makes sense to have one set for development and testing (that accepts redirects to f.e. http://localhost:8080/connect/oauth2callback when you run the service locally and https://test.myservice.example.com/connect/oauth2callback for your testing environment) and another set for your production service (that only allows the redirect URI to be set to https://myservice.example.com/connect/complete).

If you want to add additional redirect URIs for your clients please do not hesitate to mail us.

Endpoints exposed by the library

  • <path>/login -- start login roundtrip
  • <path>/oauth2callback -- OAuth callback
  • <path>/logout -- start logout roundtrip
  • <path>/logoutcallback -- start logout roundtrip

You can add a session endpoint that shows the logged in user's properties by adding this to your code:

http.HandleFunc("/connect/profile", connect.SessionProfile)

Demo client setup

Client ID:   telenordigital-connectexample-web
RedirectURI: http://localhost:8080/oauth2callback (login complete)
             http://localhost:8080/logoutcallback (logout complete)

Auth init: https://connect.telenordigital.com/oauth/authorize
Logout init: https://connect.telenordigital.com/oauth/logout
Token endpoint: https://connect.telenordigital.com/oauth/token
JWK endpoint: https://connect.telenordigital.com/oauth/public_keys.jwks

Documentation

Overview

Package goconnect is an authentication library for the Telenor CONNECT ID service.

The go-connectid library is an easy-to-use library when you want to integrate with the Telenor CONNECT ID service. It can be retrofitted to any http service that uses the http package with a few simple changes in the service setup.

Creating a new client

Start by creating a new client configuration and Connect client:

config := connect.NewDefaultConfig(ClientConfig{
    Host:                      connect.StagingHost,
    ClientID:                  username,
    Password:                  password,
    LoginCompleteRedirectURI:  "/main.html",
    LogoutCompleteRedirectURI: "/",
})

connectid := connect.NewConnectID(config)

Setting up the HTTP mux

Once the client is created you can wrap the http.Handler and http.HandlerFunc elements in your server:

// This the default start page. It uses the unwrapped handler since it
// won't require authentication
http.HandleFunc("/", startPageHandler)

// This page will require authentication
http.HandleFunc("/main.html", connectid.NewAuthHandlerFunc(mainPageHandler))

// Protected resources requires authentication
http.Handle("/extra/", connectid.NewAuthHandler(
    http.StripPrefix("/extra/", http.FileServer(http.Dir("html/extra")))))

// API endpoint - requires authentication
http.HandleFunc("/api/oneliner", connectid.NewAuthHandlerFunc(api.OneLinerHandlerFunc))

The session object is stored into the http.Request context. Retrieve the context with the SessionContext key:

// Write the logged in user's name
func myHandlerFunc(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    w.Header().Set("Content-Type", "text/plain")

    session := r.Context().Value(connect.SessionContext)
    w.Write([]byte("Hello, ", session.Name))
}

The callbacks for the OAuth service must be set up according to your configuration.

The default development client is set up to redirect to http://localhost:8080/connect/complete and http://localhost:8080/connect/login and the Go-Connect handler is set up the following way:

http.Handle("/connect/", connectid.Handler())

Index

Examples

Constants

View Source
const (
	// DefaultHost is the Connect ID production host. We recommend using this.
	DefaultHost = "connect.telenordigital.com"

	// StagingHost is the host name for the staging (aka testing) environment
	StagingHost = "connect.staging.telenordigital.com"
)
View Source
const (
	DefaultScopes                    = "openid profile email phone"
	DefaultLoginInit                 = "login"
	DefaultLogoutInit                = "logout"
	DefaultLoginRedirectURI          = "http://localhost:8080/connect/oauth2callback"
	DefaultLogoutRedirectURI         = "http://localhost:8080/connect/logoutcallback"
	DefaultLoginRedirect             = "oauth2callback"
	DefaultLogoutRedirect            = "logoutcallback"
	DefaultLoginCompleteRedirectURI  = "/"
	DefaultLogoutCompleteRedirectURI = "/"
	DefaultProfileEndpoint           = "profile"
)

These constants provide default values for ClientConfig.

View Source
const (
	// SessionContext is the identifier for the http.Request context. Use this to access the
	// session object when the NewHandlerFunc has wrapped a HandlerFunc.
	SessionContext contextKey = "connect-session"
)

Variables

View Source
var SQLSchema = []string{
	`CREATE TABLE IF NOT EXISTS sessions (
		session_id VARCHAR(128) NOT NULL,
		session_data TEXT,
		expires BIGINT NOT NULL,
		CONSTRAINT sessions_pk PRIMARY KEY (session_id))`,
	"CREATE INDEX IF NOT EXISTS sessions_expired ON sessions(expires)",
	`CREATE TABLE IF NOT EXISTS nonces (
		nonce VARCHAR(128) NOT NULL,
		created BIGINT NOT NULL,
		type SMALLINT NOT NULL,
		CONSTRAINT nonces_pk PRIMARY KEY (nonce))`,
	"CREATE INDEX IF NOT EXISTS nonces_created ON nonces(created)",
	"CREATE INDEX IF NOT EXISTS nonces_type ON nonces(type)",
}

SQLSchema contains DDL statements for the backend store. The statements works on both SQLite and PostgreSQL. They must be executed in the order they are returned.

Functions

func HasSessionCookie added in v0.7.0

func HasSessionCookie(r *http.Request) bool

HasSessionCookie returns true if the request contains a CONNECT ID session cookie

func SQLStorePrepare added in v0.7.0

func SQLStorePrepare(db *sql.DB) error

SQLStorePrepare runs the DDL statements on the database.

Types

type ClientConfig

type ClientConfig struct {
	Host                      string // Host is the name of the Connect ID host to use.
	Scopes                    string // Scopes is a space separated list of the OAuth scopes to use when logging in.
	ClientID                  string // ClientID is the OAuth client ID.
	Password                  string // Password is the (optional) secret.
	LoginInit                 string // LoginInit is the endpoint for starting a login.
	LogoutInit                string // LogoutInit is the endpoint for starting a logout.
	LoginRedirectURI          string // LoginRedirectURI is where the OAuth server redirects after a successful login.
	LogoutRedirectURI         string // LogoutRedirectURI is where the OAuth server redirects after a successful logout.
	LoginRedirect             string // LoginRedirect is the endpoint that serves - and is thus typically a suffix of - LoginRedirectURI.
	LogoutRedirect            string // LogoutRedirect is the endpoint that serves - and is thus typically a suffix of - LogoutRedirectURI.
	LoginCompleteRedirectURI  string // LoginCompleteRedirectURI is where goconnect redirects after a successful login.
	LogoutCompleteRedirectURI string // LogoutCompleteRedirectURI is where goconnect redirects after a successfull logout.
	ProfileEndpoint           string // ProfileEndpoint is the session profile information endpoint.
	UseSecureCookie           bool   // UseSecureCookie indicates whether to use a secure cookie.
}

ClientConfig holds the ConnectID configuration.

func NewDefaultConfig

func NewDefaultConfig(overrides ClientConfig) ClientConfig

NewDefaultConfig creates a configuration with default values prepopulated. If the parameter is set in the overrides parameter it won't be set.

Example
config := NewDefaultConfig(ClientConfig{
	Host:                      StagingHost,
	ClientID:                  "client-id",
	Password:                  "client-secret",
	LoginCompleteRedirectURI:  "/main.html",
	LogoutCompleteRedirectURI: "/",
})

fmt.Println(config.LoginCompleteRedirectURI)
fmt.Println(config.LogoutCompleteRedirectURI)
Output:

/main.html
/

type GoConnect

type GoConnect struct {
	Config ClientConfig
	// contains filtered or unexported fields
}

GoConnect is the main entry point to Telenor CONNECT ID client API.

func NewConnectID

func NewConnectID(config ClientConfig) *GoConnect

NewConnectID creates a new ConnectID client usign the default (memory-based) storage.

func NewConnectIDWithStorage added in v0.7.0

func NewConnectIDWithStorage(config ClientConfig, storage Storage) *GoConnect

NewConnectIDWithStorage creates a new ConnectID client with the specified storage implementation.

func (*GoConnect) Handler

func (t *GoConnect) Handler() http.Handler

Handler returns a http.Handler that will respond on the following endpoints:

Config.LoginInit to start a login roundtrip towards the OAuth server
Config.LoginRedirect for the OAuth redirect when login is complete
Config.LogoutInit to start a logout roundtrip towards the OAuth server
Config.LogoutRedirect for the OAuth redirect when logout is complete

The Init endpoints are the ones you navigate to to initiate the action. The Redirect endpoints are redirected to from the OAuth server when it is complete.

func (*GoConnect) NewAuthHandler

func (t *GoConnect) NewAuthHandler(existingHandler http.Handler) http.Handler

NewAuthHandler returns a http.Handler that requires authentication. If the request isn't authenticated a 401 Unauthorized is returned to the client, otherwise the existing http.Handler is invoked. The Session object is passed along in the request's Context.

func (*GoConnect) NewAuthHandlerFunc

func (t *GoConnect) NewAuthHandlerFunc(existingFunc http.HandlerFunc) http.HandlerFunc

NewAuthHandlerFunc returns a http.HandlerFunc that requires authentication. If the request isn't authenticated a 401 Unauthorized is returned, otherwise the existing http.HandlerFunc will be called as normal. The session object is passed along in the request's Context object.

func (*GoConnect) SessionProfile

func (t *GoConnect) SessionProfile(w http.ResponseWriter, r *http.Request)

SessionProfile is a premade session endpoint that you can use to serve the profile information to the end user. Since this resource might be used by JavaScript clients it would potentially need CORS headers and a matching OPTIONS header but this might introduce security issues. Add the header to the default mux by using the following snippet:

http.HandleFunc("/connect/profile", connect.SessionProfile)

type Session

type Session struct {
	UserID        string `json:"connect_id"`     // Connect ID
	Name          string `json:"name"`           // Name (might be blank)
	Locale        string `json:"locale"`         // Locale (might be blank)
	Email         string `json:"email"`          // Email (might be blank)
	VerifiedEmail bool   `json:"verified_email"` // Email is verified
	Phone         string `json:"phone"`          // Phone # (might be blank)
	VerifiedPhone bool   `json:"verified_phone"` // Verified phone
	// contains filtered or unexported fields
}

Session holds the session information from the CONNECT ID OAuth server.

type Storage

type Storage interface {
	// Add state nonce to storage. This is disposable and will expire in 20 minutes
	PutLoginNonce(token string) error

	// Retrieve and remove nonce (if it exists) from storage
	CheckLoginNonce(token string) error

	// Add state nonce to storage. This is disposable and will expire in 20 minutes
	PutLogoutNonce(token string) error

	// Retrieve and remove nonce (if it exists) from storage
	CheckLogoutNonce(token string) error

	// PutSession creates a new session identifier and stores
	// the information in a session structure
	PutSession(session Session) error

	// GetSession returns the session associated with the session ID.
	GetSession(sessionid string) (Session, error)

	// DeleteSession removes the session
	DeleteSession(sessionid string)

	//UpdateSession updates a session in the backend store
	UpdateSession(Session) error

	// ListSessions lists all of the sessions in the backend store.
	ListSessions() ([]Session, error)

	// RemoveExpiredNonces removes all of the expired nonces from the store
	RemoveExpiredNonces()
}

Storage is the session and nonce storage used by the go-connectid client. The default session and nonce storage is memory-based. It works perfectly fine for a single-server installation but if you run more than one server you probably want to use a different backend such as Memcached or Redis for session storage.

The storage implementation is responsible for expiring nonces automatically. RefreshTokens is used to refresh access tokens against the OAuth server.

func NewMemoryStorage

func NewMemoryStorage() Storage

NewMemoryStorage creates a new memory-backed storage implementation. This implementation is suitable for single-server solution. If you are running on more than one server this must be implemented as a common storage, ie. in some sort of database. The stored data is just nonces and sessions so data integrity isn't the most critical aspect. A storage backed by Memcached or Redis would be ideal for this.

func NewSQLStorage added in v0.7.0

func NewSQLStorage(db *sql.DB) (Storage, error)

NewSQLStorage creates a new SQL-backed storage

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL