Skip to content

Added support for msgraph #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module github.com/deploymenttheory/go-api-http-client-integrations/jamfpro/jamfprointegration
module github.com/deploymenttheory/go-api-http-client-integrations


go 1.22.4

Expand Down
14 changes: 14 additions & 0 deletions jamfpro/jamfprointegration/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,20 @@ type authInterface interface {
tokenEmpty() bool
}

// checkRefreshToken checks and refreshes the authentication token if necessary.
// This function ensures that the authentication token is valid and not expired. If the token is empty, expired,
// or within the buffer period before expiry, it attempts to obtain a new token and validates the new token's lifetime
// against the buffer period to prevent infinite loops.
//
// Returns:
// - error: Any error encountered during the token refresh process or if the token's lifetime is shorter than the buffer period. Returns nil if no errors occur.
//
// Functionality:
// - Logs a warning if the token is empty.
// - Checks if the token is expired, within the buffer period, or empty.
// - Attempts to obtain a new token if the current token is invalid.
// - Validates the new token's lifetime against the buffer period to prevent bad token lifetime/buffer combinations.
// - Returns an error if the token refresh fails or if the new token's lifetime is shorter than the buffer period.
func (j *Integration) checkRefreshToken() error {
var err error

Expand Down
46 changes: 40 additions & 6 deletions jamfpro/jamfprointegration/auth_basic.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,21 @@ type basicAuthResponse struct {

// Operations

// TODO comment
// getNewToken obtains a new bearer token from the authentication server.
// This function constructs a new HTTP request to the bearer token endpoint using the basic authentication credentials,
// sends the request, and updates the basicAuth instance with the new bearer token and its expiry time.
//
// Returns:
// - error: Any error encountered during the request, response handling, or JSON decoding. Returns nil if no errors occur.
//
// Functionality:
// - Constructs the complete bearer token endpoint URL.
// - Creates a new HTTP POST request and sets the basic authentication headers.
// - Sends the request using an HTTP client and checks the response status.
// - Decodes the JSON response to obtain the bearer token and its expiry time.
// - Updates the basicAuth instance with the new bearer token and its expiry time.
// - Logs the successful token retrieval with the expiry time and duration.
//
// TODO migrate strings
func (a *basicAuth) getNewToken() error {
client := http.Client{}
Expand Down Expand Up @@ -70,24 +84,40 @@ func (a *basicAuth) getNewToken() error {
return nil
}

// TODO comment
// getTokenString returns the current bearer token as a string.
// This function provides access to the current bearer token stored in the basicAuth instance.
//
// Returns:
// - string: The current bearer token.
func (a *basicAuth) getTokenString() string {
return a.bearerToken
}

// TODO comment
// getExpiryTime returns the expiry time of the current bearer token.
// This function provides access to the expiry time of the current bearer token stored in the basicAuth instance.
//
// Returns:
// - time.Time: The expiry time of the current bearer token.
func (a *basicAuth) getExpiryTime() time.Time {
return a.bearerTokenExpiryTime
}

// Utils

// TODO comment
// tokenExpired checks if the current bearer token has expired.
// This function compares the current time with the bearer token's expiry time to determine if the token has expired.
//
// Returns:
// - bool: True if the bearer token has expired, false otherwise.
func (a *basicAuth) tokenExpired() bool {
return a.bearerTokenExpiryTime.Before(time.Now())
}

// TODO comment
// tokenInBuffer checks if the current bearer token is within the buffer period before expiry.
// This function calculates the remaining time until the token expires and compares it with the buffer period.
//
// Returns:
// - bool: True if the bearer token is within the buffer period, false otherwise.
func (a *basicAuth) tokenInBuffer() bool {
if time.Until(a.bearerTokenExpiryTime) <= a.bufferPeriod {
return true
Expand All @@ -96,7 +126,11 @@ func (a *basicAuth) tokenInBuffer() bool {
return false
}

// TODO comment
// tokenEmpty checks if the current bearer token is empty.
// This function determines if the bearer token string stored in the basicAuth instance is empty.
//
// Returns:
// - bool: True if the bearer token is empty, false otherwise.
func (a *basicAuth) tokenEmpty() bool {
if a.bearerToken == "" {
return true
Expand Down
1 change: 1 addition & 0 deletions jamfpro/jamfprointegration/headers.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func (j *Integration) getAcceptHeader() string {
return weightedAcceptHeader
}

// getUserAgentHeader returns the User-Agent header string for the Jamf Pro API.
func (j *Integration) getUserAgentHeader() string {
return "go-api-http-client-jamfpro-integration"
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// jamfpro_api_request.go
// jamfpro/jamfprointegration/marshall.go
package jamfprointegration

import (
Expand All @@ -11,10 +11,30 @@ import (
"path/filepath"
"strings"

"github.com/deploymenttheory/go-api-http-client-integrations/shared/helpers"
"go.uber.org/zap"
)

// MarshalRequest encodes the request body according to the endpoint for the API.
// MarshalRequest encodes the request body according to the endpoint for the Jamf Pro API.
// This function marshals the request body as JSON or XML based on the endpoint string.
// It takes an interface{} type body, an HTTP method, and an endpoint as input, and returns the
// marshaled byte slice along with any error encountered during marshaling.
//
// Parameters:
// - body: The request body to be marshaled, of type interface{}.
// - method: The HTTP method being used for the request (e.g., "POST", "PUT", "PATCH").
// - endpoint: The API endpoint for the request.
//
// Returns:
// - []byte: The marshaled byte slice of the request body.
// - error: Any error encountered during the marshaling process.
//
// Functionality:
// - Determines the format (JSON or XML) based on the endpoint string.
// - Marshals the body as JSON if the endpoint contains "/api" or as XML if it contains "/JSSResource".
// - Logs the marshaled request body for POST, PUT, and PATCH methods using the integrated logger.
// - Logs an error if marshaling fails and returns the error.
// - Returns an error if the format is invalid.
func (j *Integration) marshalRequest(body interface{}, method string, endpoint string) ([]byte, error) {
var (
data []byte
Expand Down Expand Up @@ -74,7 +94,7 @@ func (j *Integration) marshalMultipartRequest(fields map[string]string, files ma
}

for formField, filePath := range files {
file, err := SafeOpenFile(filePath)
file, err := helpers.SafeOpenFile(filePath)
if err != nil {
j.Logger.Error("Failed to open file securely", zap.String("file", filePath), zap.Error(err))
return nil, "", err
Expand Down
17 changes: 16 additions & 1 deletion jamfpro/jamfprointegration/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,22 @@ import (
"net/http"
)

// TODO func comment
// prepRequest prepares an HTTP request by setting the necessary headers and handling authorization.
// This function adds headers for Accept, Content-Type, User-Agent, and Authorization based on the Integration's methods
// and checks for token refresh if needed.
//
// Parameters:
// - req: A pointer to the http.Request that needs to be prepared.
//
// Returns:
// - error: Any error encountered while checking the refresh token or setting headers. Returns nil if no errors occur.
//
// Functionality:
// - Adds an "Accept" header based on the Integration's getAcceptHeader method.
// - Adds a "Content-Type" header based on the Integration's getContentTypeHeader method, which depends on the request URL.
// - Adds a "User-Agent" header based on the Integration's getUserAgentHeader method.
// - Checks and refreshes the token if necessary using the Integration's checkRefreshToken method.
// - Adds an "Authorization" header with a Bearer token obtained from the Integration's auth.getTokenString method.
func (j *Integration) prepRequest(req *http.Request) error {
req.Header.Add("Accept", j.getAcceptHeader())
req.Header.Add("Content-Type", j.getContentTypeHeader(req.URL.String()))
Expand Down
5 changes: 2 additions & 3 deletions jamfpro/jamfprointegration/urls.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// jamfpro_api_url.go
// jamfpro/jamfprointegration/urls.go
package jamfprointegration

// SetBaseDomain returns the appropriate base domain for URL construction.
// It uses j.OverrideBaseDomain if set, otherwise falls back to DefaultBaseDomain.
// GetBaseDomain returns the base domain for the Jamf Pro integration.
func (j *Integration) GetBaseDomain() string {
return j.BaseDomain
}
63 changes: 63 additions & 0 deletions msgraph/msgraphintegration/auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// msgraph/msgraphintegration/auth.go
package msgraphintegration

import (
"errors"
"time"
)

const (
tokenEmptyWarnString = "token empty before processing - disregard if first run"
)

// authInterface defines the methods required to satify the authentication interface.
type authInterface interface {
// Token Operations
getNewToken() error
getTokenString() string
getExpiryTime() time.Time

// Token Utils
tokenExpired() bool
tokenInBuffer() bool
tokenEmpty() bool
}

// checkRefreshToken checks and refreshes the authentication token if necessary.
// This function ensures that the authentication token is valid and not expired. If the token is empty, expired,
// or within the buffer period before expiry, it attempts to obtain a new token and validates the new token's lifetime
// against the buffer period to prevent infinite loops.
//
// Returns:
// - error: Any error encountered during the token refresh process or if the token's lifetime is shorter than the buffer period. Returns nil if no errors occur.
//
// Functionality:
// - Logs a warning if the token is empty.
// - Checks if the token is expired, within the buffer period, or empty.
// - Attempts to obtain a new token if the current token is invalid.
// - Validates the new token's lifetime against the buffer period to prevent bad token lifetime/buffer combinations.
// - Returns an error if the token refresh fails or if the new token's lifetime is shorter than the buffer period.
func (m *Integration) checkRefreshToken() error {
var err error

if m.auth.tokenEmpty() {
m.Logger.Warn(tokenEmptyWarnString)
}

if m.auth.tokenExpired() || m.auth.tokenInBuffer() || m.auth.tokenEmpty() {
err = m.auth.getNewToken()

if err != nil {
return err
}

// Protects against bad token lifetime/buffer combinations (infinite loops)
if m.auth.tokenExpired() || m.auth.tokenInBuffer() {
return errors.New("token lifetime is shorter than buffer period. please adjust parameters")
}

return nil
}

return nil
}
Loading