Skip to content
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

Resolve several minor issues #1393

Merged
merged 5 commits into from
Apr 27, 2019
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
22 changes: 21 additions & 1 deletion UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ before finalizing the upgrade process.


- [Hassle-free upgrades](#hassle-free-upgrades)
- [1.0.0-rc.10](#100-rc10)
- [SQL Migrations now require user-input or `--yes` flag](#sql-migrations-now-require-user-input-or---yes-flag)
- [Login and Consent Management](#login-and-consent-management)
- [1.0.0-rc.9](#100-rc9)
- [Go SDK](#go-sdk)
- [Accepting Login and Consent Requests](#accepting-login-and-consent-requests)
- [1.0.0-rc.7](#100-rc7)
- [Configuration changes](#configuration-changes)
- [System secret rotation](#system-secret-rotation)
Expand Down Expand Up @@ -89,7 +95,7 @@ before finalizing the upgrade process.
- [New consent flow](#new-consent-flow)
- [Audience](#audience)
- [Response payload changes to `/warden/token/allowed`](#response-payload-changes-to-wardentokenallowed)
- [Go SDK](#go-sdk)
- [Go SDK](#go-sdk-1)
- [Health endpoints](#health-endpoints)
- [Group endpoints](#group-endpoints)
- [Replacing hierarchical scope strategy with wildcard scope strategy](#replacing-hierarchical-scope-strategy-with-wildcard-scope-strategy)
Expand Down Expand Up @@ -133,6 +139,20 @@ secure deployment with zero effort? We can run it for you! If you're interested,

## 1.0.0-rc.10

### Schema Changes

Please read all paragraphs of this section with the utmost care, before executing `hydra migrate sql`. Do
not take this change lightly and create a backup of the database before you begin. To be sure, copy the database
and do a dry-run locally.

> Be aware that running these migrations might take some time when using large databases. Do a dry-run before hammering
your production database.

### SQL Migrations now require user-input or `--yes` flag

`hydra migrate sql` now shows an execution plan and asks for confirmation before executing the migrations. To run
migrations without user interaction, add flag `--yes`.

### Login and Consent Management

Orthogonal to the changes when accepting and rejection consent and login requests, the following endpoints
Expand Down
8 changes: 7 additions & 1 deletion client/manager_sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import (
"github.com/pkg/errors"
migrate "github.com/rubenv/sql-migrate"
"github.com/sirupsen/logrus"
jose "gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2"

"github.com/ory/fosite"
"github.com/ory/x/dbal"
Expand Down Expand Up @@ -225,6 +225,12 @@ func (d *sqlData) ToClient() (*Client, error) {
return c, nil
}

func (m *SQLManager) PlanMigration() ([]*migrate.PlannedMigration, error) {
migrate.SetTable("hydra_client_migration")
plan, _, err := migrate.PlanMigration(m.DB.DB, m.DB.DriverName(), Migrations[dbal.Canonicalize(m.DB.DriverName())], migrate.Up, 0)
return plan, errors.WithStack(err)
}

func (m *SQLManager) CreateSchemas() (int, error) {
migrate.SetTable("hydra_client_migration")
n, err := migrate.Exec(m.DB.DB, m.DB.DriverName(), Migrations[dbal.Canonicalize(m.DB.DriverName())], migrate.Up)
Expand Down
36 changes: 36 additions & 0 deletions cmd/cli/handler_migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
package cli

import (
"bufio"
"fmt"
"os"
"strings"

"github.com/spf13/cobra"
"github.com/spf13/viper"
Expand Down Expand Up @@ -72,7 +74,41 @@ func (h *MigrateHandler) MigrateSQL(cmd *cobra.Command, args []string) {
return
}

plan, err := reg.SchemaMigrationPlan()
cmdx.Must(err, "An error occurred planning migrations: %s", err)

fmt.Println("The following migration is planned:")
fmt.Println("")
plan.Render()

if !flagx.MustGetBool(cmd, "yes") {
fmt.Println("")
fmt.Println("To skip the next question use flag --yes (at your own risk).")
if !askForConfirmation("Do you wish to execute this migration plan?") {
fmt.Println("Migration aborted.")
return
}
}

n, err := reg.CreateSchemas()
cmdx.Must(err, "An error occurred while connecting to SQL: %s", err)
fmt.Printf("Successfully applied %d SQL migrations!\n", n)
}

func askForConfirmation(s string) bool {
reader := bufio.NewReader(os.Stdin)

for {
fmt.Printf("%s [y/n]: ", s)

response, err := reader.ReadString('\n')
cmdx.Must(err, "%s", err)

response = strings.ToLower(strings.TrimSpace(response))
if response == "y" || response == "yes" {
return true
} else if response == "n" || response == "no" {
return false
}
}
}
1 change: 1 addition & 0 deletions cmd/migrate_sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,5 @@ func init() {
migrateCmd.AddCommand(migrateSqlCmd)

migrateSqlCmd.Flags().BoolP("read-from-env", "e", false, "If set, reads the database connection string from the environment variable DSN.")
migrateSqlCmd.Flags().BoolP("yes", "y", false, "If set all confirmation requests are accepted without user interaction.")
}
24 changes: 21 additions & 3 deletions cmd/server/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,24 +188,42 @@ func setup(d driver.Driver, cmd *cobra.Command) (admin *x.RouterAdmin, public *x
strings.Contains(d.Configuration().IssuerURL().String(), "localhost"),
WriteKey: "h8dRH3kVCWKkIFWydBmWsyYHR4M0u0vr",
WhitelistedPaths: []string{
client.ClientsHandlerPath,
jwk.KeyHandlerPath,
jwk.WellKnownKeysPath,

client.ClientsHandlerPath,

oauth2.DefaultConsentPath,
oauth2.DefaultLoginPath,
oauth2.DefaultPostLogoutPath,
oauth2.DefaultLogoutPath,
oauth2.DefaultErrorPath,
oauth2.TokenPath,
oauth2.AuthPath,
oauth2.LogoutPath,
oauth2.UserinfoPath,
oauth2.WellKnownPath,
oauth2.JWKPath,
oauth2.IntrospectPath,
oauth2.RevocationPath,
oauth2.FlushPath,

consent.ConsentPath,
consent.ConsentPath + "/accept",
consent.ConsentPath + "/reject",
consent.LoginPath,
consent.LoginPath + "/accept",
consent.LoginPath + "/reject",
consent.LogoutPath,
consent.LogoutPath + "/accept",
consent.LogoutPath + "/reject",
consent.SessionsPath + "/login",
consent.SessionsPath + "/consent",

healthx.AliveCheckPath,
healthx.ReadyCheckPath,
healthx.VersionPath,
driver.MetricsPrometheusPath,
"/oauth2/auth/sessions/login",
"/oauth2/auth/sessions/consent",
"/",
},
BuildVersion: d.Registry().BuildVersion(),
Expand Down
3 changes: 2 additions & 1 deletion consent/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ func (h *Handler) GetConsentSessions(w http.ResponseWriter, r *http.Request, ps
// Invalidates a subject's authentication session
//
// This endpoint invalidates a subject's authentication session. After revoking the authentication session, the subject
// has to re-authenticate at ORY Hydra. This endpoint does not invalidate any tokens.
// has to re-authenticate at ORY Hydra. This endpoint does not invalidate any tokens and does not work with OpenID Connect
// Front- or Back-channel logout.
//
//
// Consumes:
Expand Down
6 changes: 6 additions & 0 deletions consent/manager_sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ func NewSQLManager(db *sqlx.DB, r InternalRegistry) *SQLManager {
}
}

func (m *SQLManager) PlanMigration() ([]*migrate.PlannedMigration, error) {
migrate.SetTable("hydra_oauth2_authentication_consent_migration")
plan, _, err := migrate.PlanMigration(m.DB.DB, m.DB.DriverName(), Migrations[dbal.Canonicalize(m.DB.DriverName())], migrate.Up, 0)
return plan, errors.WithStack(err)
}

func (m *SQLManager) CreateSchemas() (int, error) {
migrate.SetTable("hydra_oauth2_authentication_consent_migration")
n, err := migrate.Exec(m.DB.DB, m.DB.DriverName(), Migrations[dbal.Canonicalize(m.DB.DriverName())], migrate.Up)
Expand Down
49 changes: 28 additions & 21 deletions cypress/helpers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,31 @@ export const prng = () =>
.toString(36)
.substring(2)}${Math.random()
.toString(36)
.substring(2)}`
.substring(2)}`;

const isStatusOk = res =>
res.ok
? Promise.resolve(res)
: Promise.reject(
new Error(`Received unexpected status code ${res.statusCode}`)
)
new Error(`Received unexpected status code ${res.statusCode}`)
);

export const findEndUserAuthorization = subject =>
fetch(Cypress.env('admin_url') + '/oauth2/auth/sessions/consent?subject='+subject)
fetch(
Cypress.env('admin_url') +
'/oauth2/auth/sessions/consent?subject=' +
subject
)
.then(isStatusOk)
.then((res) => res.json())
.then(res => res.json());

export const revokeEndUserAuthorization = subject =>
fetch(Cypress.env('admin_url') + '/oauth2/auth/sessions/consent?subject='+subject, { method: 'DELETE' })
.then(isStatusOk)
fetch(
Cypress.env('admin_url') +
'/oauth2/auth/sessions/consent?subject=' +
subject,
{ method: 'DELETE' }
).then(isStatusOk);

export const createClient = client =>
fetch(Cypress.env('admin_url') + '/clients', {
Expand All @@ -29,7 +37,7 @@ export const createClient = client =>
})
.then(isStatusOk)
.then(res => {
return res.json()
return res.json();
})
.then(body =>
getClient(client.client_id).then(actual => {
Expand All @@ -38,32 +46,31 @@ export const createClient = client =>
new Error(
`Expected client_id's to match: ${actual.client_id} !== ${
body.client
}`
}`
)
)
);
}

return Promise.resolve(body)
return Promise.resolve(body);
})
)
);

export const deleteClients = () =>
fetch(Cypress.env('admin_url') + '/clients', {
method: 'GET',
method: 'GET'
})
.then(isStatusOk)
.then((res) => res.json())
.then((body) => {
body.forEach(({ client_id }) => deleteClient(client_id))
})
.then(res => res.json())
.then(body => {
body.forEach(({ client_id }) => deleteClient(client_id));
});

const deleteClient = client_id =>
fetch(Cypress.env('admin_url') + '/clients/' + client_id, {
method: 'DELETE',
})
.then(isStatusOk)
method: 'DELETE'
}).then(isStatusOk);

const getClient = id =>
fetch(Cypress.env('admin_url') + '/clients/' + id)
.then(isStatusOk)
.then((res) => res.json())
.then(res => res.json());
Loading