mirror of
https://github.com/google/nomulus
synced 2026-05-21 23:31:51 +00:00
Compare commits
4 Commits
nomulus-20
...
nomulus-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66513a114e | ||
|
|
0e808a4c01 | ||
|
|
4e013603be | ||
|
|
730585cd14 |
@@ -119,6 +119,7 @@ if (environment == '') {
|
||||
|
||||
rootProject.ext.environment = environment
|
||||
rootProject.ext.gcpProject = gcpProject
|
||||
rootProject.ext.baseDomain = baseDomains[environment]
|
||||
rootProject.ext.prodOrSandboxEnv = environment in ['production', 'sandbox']
|
||||
|
||||
// Function to verify that the deployment parameters have been set.
|
||||
|
||||
@@ -69,7 +69,9 @@ task deploy(type: Exec) {
|
||||
}
|
||||
|
||||
tasks.buildConsoleWebappProd.dependsOn(tasks.npmInstallDeps)
|
||||
tasks.runConsoleWebappUnitTests.dependsOn(tasks.npmInstallDeps)
|
||||
tasks.applyFormatting.dependsOn(tasks.npmInstallDeps)
|
||||
tasks.checkFormatting.dependsOn(tasks.npmInstallDeps)
|
||||
tasks.build.dependsOn(tasks.checkFormatting)
|
||||
tasks.build.dependsOn(tasks.runConsoleWebappUnitTests)
|
||||
tasks.deploy.dependsOn(tasks.buildConsoleWebappProd)
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
customLaunchers: {
|
||||
ChromeHeadless: {
|
||||
base: 'Chrome',
|
||||
flags: [
|
||||
'--no-sandbox',
|
||||
'--disable-gpu',
|
||||
'--headless',
|
||||
'--remote-debugging-port=9222'
|
||||
]
|
||||
}
|
||||
},
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
|
||||
@@ -17,6 +17,9 @@ import { Route, RouterModule } from '@angular/router';
|
||||
import { BillingInfoComponent } from './billingInfo/billingInfo.component';
|
||||
import { DomainListComponent } from './domains/domainList.component';
|
||||
import { HomeComponent } from './home/home.component';
|
||||
import { RegistryLockVerifyComponent } from './lock/registryLockVerify.component';
|
||||
import { NewOteComponent } from './ote/newOte.component';
|
||||
import { OteStatusComponent } from './ote/oteStatus.component';
|
||||
import { RegistrarDetailsComponent } from './registrar/registrarDetails.component';
|
||||
import { RegistrarComponent } from './registrar/registrarsTable.component';
|
||||
import { ResourcesComponent } from './resources/resources.component';
|
||||
@@ -26,7 +29,6 @@ import { SettingsComponent } from './settings/settings.component';
|
||||
import UsersComponent from './settings/users/users.component';
|
||||
import WhoisComponent from './settings/whois/whois.component';
|
||||
import { SupportComponent } from './support/support.component';
|
||||
import { RegistryLockVerifyComponent } from './lock/registryLockVerify.component';
|
||||
|
||||
export interface RouteWithIcon extends Route {
|
||||
iconName?: string;
|
||||
@@ -38,6 +40,14 @@ export const routes: RouteWithIcon[] = [
|
||||
path: RegistryLockVerifyComponent.PATH,
|
||||
component: RegistryLockVerifyComponent,
|
||||
},
|
||||
{
|
||||
path: NewOteComponent.PATH,
|
||||
component: NewOteComponent,
|
||||
},
|
||||
{
|
||||
path: OteStatusComponent.PATH,
|
||||
component: OteStatusComponent,
|
||||
},
|
||||
{ path: 'registrars', component: RegistrarComponent },
|
||||
{
|
||||
path: 'home',
|
||||
|
||||
@@ -30,7 +30,10 @@ import { DomainListComponent } from './domains/domainList.component';
|
||||
import { RegistryLockComponent } from './domains/registryLock.component';
|
||||
import { HeaderComponent } from './header/header.component';
|
||||
import { HomeComponent } from './home/home.component';
|
||||
import { RegistryLockVerifyComponent } from './lock/registryLockVerify.component';
|
||||
import { NavigationComponent } from './navigation/navigation.component';
|
||||
import { NewOteComponent } from './ote/newOte.component';
|
||||
import { OteStatusComponent } from './ote/oteStatus.component';
|
||||
import NewRegistrarComponent from './registrar/newRegistrar.component';
|
||||
import { RegistrarDetailsComponent } from './registrar/registrarDetails.component';
|
||||
import { RegistrarSelectorComponent } from './registrar/registrarSelector.component';
|
||||
@@ -54,7 +57,6 @@ import { UserDataService } from './shared/services/userData.service';
|
||||
import { SnackBarModule } from './snackbar.module';
|
||||
import { SupportComponent } from './support/support.component';
|
||||
import { TldsComponent } from './tlds/tlds.component';
|
||||
import { RegistryLockVerifyComponent } from './lock/registryLockVerify.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@@ -66,6 +68,8 @@ import { RegistryLockVerifyComponent } from './lock/registryLockVerify.component
|
||||
HeaderComponent,
|
||||
HomeComponent,
|
||||
LocationBackDirective,
|
||||
NewOteComponent,
|
||||
OteStatusComponent,
|
||||
UserLevelVisibility,
|
||||
NavigationComponent,
|
||||
NewRegistrarComponent,
|
||||
|
||||
@@ -20,6 +20,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { BackendService } from '../shared/services/backend.service';
|
||||
import { DomainListComponent } from './domainList.component';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
describe('DomainListComponent', () => {
|
||||
let component: DomainListComponent;
|
||||
@@ -28,7 +29,7 @@ describe('DomainListComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [DomainListComponent],
|
||||
imports: [MaterialModule, BrowserAnimationsModule],
|
||||
imports: [MaterialModule, BrowserAnimationsModule, FormsModule],
|
||||
providers: [
|
||||
BackendService,
|
||||
provideHttpClient(),
|
||||
|
||||
36
console-webapp/src/app/ote/newOte.component.html
Normal file
36
console-webapp/src/app/ote/newOte.component.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<h1 class="mat-headline-4">Generate OT&E Accounts</h1>
|
||||
<div class="console-app__new-ote">
|
||||
@if (oteCreateResponseFormatted()) {
|
||||
<h1>Generated Successfully</h1>
|
||||
<mat-card appearance="outlined">
|
||||
<mat-card-header>
|
||||
<mat-card-title>Epp Credentials</mat-card-title>
|
||||
<mat-card-subtitle
|
||||
>Copy and paste this into an email to the registrars</mat-card-subtitle
|
||||
>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<p>{{ oteCreateResponseFormatted() }}</p>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
} @else {
|
||||
<form (ngSubmit)="onSubmit()" [formGroup]="createOte">
|
||||
<p>
|
||||
<mat-form-field name="registrarId" appearance="outline">
|
||||
<mat-label>Base Registrar Id: </mat-label>
|
||||
<input matInput type="text" formControlName="registrarId" required />
|
||||
</mat-form-field>
|
||||
</p>
|
||||
<p>
|
||||
<mat-form-field name="registrarEmail" appearance="outline">
|
||||
<mat-label>Contact Email: </mat-label>
|
||||
<input matInput type="text" formControlName="registrarEmail" required />
|
||||
<mat-hint
|
||||
>Will be granted web-console access to the OTE registrars.</mat-hint
|
||||
>
|
||||
</mat-form-field>
|
||||
</p>
|
||||
<button mat-flat-button color="primary" type="submit">Save</button>
|
||||
</form>
|
||||
}
|
||||
</div>
|
||||
7
console-webapp/src/app/ote/newOte.component.scss
Normal file
7
console-webapp/src/app/ote/newOte.component.scss
Normal file
@@ -0,0 +1,7 @@
|
||||
.console-app__new-ote {
|
||||
max-width: 720px;
|
||||
mat-card-content {
|
||||
white-space: break-spaces;
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
81
console-webapp/src/app/ote/newOte.component.ts
Normal file
81
console-webapp/src/app/ote/newOte.component.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright 2024 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Component, computed, signal } from '@angular/core';
|
||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { RegistrarService } from '../registrar/registrar.service';
|
||||
|
||||
export interface OteCreateResponse extends Map<string, string> {
|
||||
password: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-ote',
|
||||
templateUrl: './newOte.component.html',
|
||||
styleUrls: ['./newOte.component.scss'],
|
||||
})
|
||||
export class NewOteComponent {
|
||||
public static PATH = 'new-ote';
|
||||
|
||||
oteCreateResponse = signal<OteCreateResponse | undefined>(undefined);
|
||||
|
||||
readonly oteCreateResponseFormatted = computed(() => {
|
||||
const oteCreateResponse = this.oteCreateResponse();
|
||||
if (oteCreateResponse) {
|
||||
const { password } = oteCreateResponse;
|
||||
return Object.entries(oteCreateResponse)
|
||||
.filter((entry) => entry[0] !== 'password')
|
||||
.map(
|
||||
([login, tld]) =>
|
||||
`Login: ${login}\t\tPassword: ${password}\t\tTLD: ${tld}`
|
||||
)
|
||||
.join('\n');
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
createOte = new FormGroup({
|
||||
registrarId: new FormControl('', [Validators.required]),
|
||||
registrarEmail: new FormControl('', [Validators.required]),
|
||||
});
|
||||
|
||||
constructor(
|
||||
protected registrarService: RegistrarService,
|
||||
private _snackBar: MatSnackBar
|
||||
) {}
|
||||
|
||||
onSubmit() {
|
||||
if (this.createOte.valid) {
|
||||
const { registrarId, registrarEmail } = this.createOte.value;
|
||||
this.registrarService
|
||||
.generateOte(
|
||||
{
|
||||
registrarId,
|
||||
registrarEmail,
|
||||
},
|
||||
registrarId || ''
|
||||
)
|
||||
.subscribe({
|
||||
next: (oteCreateResponse: OteCreateResponse) => {
|
||||
this.oteCreateResponse.set(oteCreateResponse);
|
||||
},
|
||||
error: (err: HttpErrorResponse) => {
|
||||
this._snackBar.open(err.error || err.message);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
31
console-webapp/src/app/ote/oteStatus.component.html
Normal file
31
console-webapp/src/app/ote/oteStatus.component.html
Normal file
@@ -0,0 +1,31 @@
|
||||
<app-selected-registrar-wrapper>
|
||||
<h1 class="mat-headline-4">OT&E Status Check</h1>
|
||||
@if(isOte()) {
|
||||
<h1 *ngIf="oteStatusResponse().length">
|
||||
Status:
|
||||
<span>{{ oteStatusUnfinished().length ? "Unfinished" : "Completed" }}</span>
|
||||
</h1>
|
||||
<div class="console-app__ote-status">
|
||||
@if(oteStatusCompleted().length) {
|
||||
<div class="console-app__ote-status_completed">
|
||||
<h1>Completed</h1>
|
||||
<div *ngFor="let entry of oteStatusCompleted()">
|
||||
<mat-icon>check_box</mat-icon>{{ entry.description }}
|
||||
</div>
|
||||
</div>
|
||||
} @if(oteStatusUnfinished().length) {
|
||||
<div class="console-app__ote-status_unfinished">
|
||||
<h1>Unfinished</h1>
|
||||
<div *ngFor="let entry of oteStatusUnfinished()">
|
||||
<mat-icon>check_box_outline_blank</mat-icon>{{ entry.description }}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
} @else {
|
||||
<h1>
|
||||
Registrar {{ registrarService.registrar()?.registrarId }} is not an OT&E
|
||||
registrar
|
||||
</h1>
|
||||
}
|
||||
</app-selected-registrar-wrapper>
|
||||
28
console-webapp/src/app/ote/oteStatus.component.scss
Normal file
28
console-webapp/src/app/ote/oteStatus.component.scss
Normal file
@@ -0,0 +1,28 @@
|
||||
.console-app__ote-status {
|
||||
max-width: 730px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
&_completed,
|
||||
&_unfinished {
|
||||
border: 1px solid #ddd;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
margin: 0 20px 30px 0;
|
||||
div {
|
||||
display: flex;
|
||||
min-width: 300px;
|
||||
align-items: flex-start;
|
||||
max-width: 300px;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 5px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
&:last-child {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
mat-icon {
|
||||
min-width: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
62
console-webapp/src/app/ote/oteStatus.component.ts
Normal file
62
console-webapp/src/app/ote/oteStatus.component.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright 2024 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Component, computed, signal } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { RegistrarService } from '../registrar/registrar.service';
|
||||
|
||||
export interface OteStatusResponse {
|
||||
description: string;
|
||||
requirement: number;
|
||||
timesPerformed: number;
|
||||
completed: boolean;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-ote-status',
|
||||
templateUrl: './oteStatus.component.html',
|
||||
styleUrls: ['./oteStatus.component.scss'],
|
||||
})
|
||||
export class OteStatusComponent {
|
||||
public static PATH = 'ote-status';
|
||||
|
||||
oteStatusResponse = signal<OteStatusResponse[]>([]);
|
||||
|
||||
oteStatusCompleted = computed(() =>
|
||||
this.oteStatusResponse().filter((v) => v.completed)
|
||||
);
|
||||
oteStatusUnfinished = computed(() =>
|
||||
this.oteStatusResponse().filter((v) => !v.completed)
|
||||
);
|
||||
isOte = computed(
|
||||
() => this.registrarService.registrar()?.type?.toLowerCase() === 'ote'
|
||||
);
|
||||
|
||||
constructor(
|
||||
protected registrarService: RegistrarService,
|
||||
private _snackBar: MatSnackBar
|
||||
) {
|
||||
this.registrarService
|
||||
.oteStatus(this.registrarService.registrarId())
|
||||
.subscribe({
|
||||
next: (oteStatusResponse: OteStatusResponse[]) => {
|
||||
this.oteStatusResponse.set(oteStatusResponse);
|
||||
},
|
||||
error: (err: HttpErrorResponse) => {
|
||||
this._snackBar.open(err.error || err.message);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,8 @@ import { Observable, switchMap, tap } from 'rxjs';
|
||||
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { Router } from '@angular/router';
|
||||
import { OteCreateResponse } from '../ote/newOte.component';
|
||||
import { OteStatusResponse } from '../ote/oteStatus.component';
|
||||
import { BackendService } from '../shared/services/backend.service';
|
||||
import {
|
||||
GlobalLoader,
|
||||
@@ -69,6 +71,7 @@ export interface Registrar
|
||||
registrarId: string;
|
||||
registrarName: string;
|
||||
registryLockAllowed?: boolean;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
@@ -149,4 +152,17 @@ export class RegistrarService implements GlobalLoader {
|
||||
loadingTimeout() {
|
||||
this._snackBar.open('Timeout loading registrars');
|
||||
}
|
||||
|
||||
generateOte(
|
||||
oteForm: Object,
|
||||
registrarId: string
|
||||
): Observable<OteCreateResponse> {
|
||||
return this.backend
|
||||
.generateOte(oteForm, registrarId)
|
||||
.pipe(tap((_) => this.loadRegistrars()));
|
||||
}
|
||||
|
||||
oteStatus(registrarId: string): Observable<OteStatusResponse[]> {
|
||||
return this.backend.getOteStatus(registrarId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,14 @@
|
||||
</button>
|
||||
<div class="spacer"></div>
|
||||
@if(!inEdit && !registrarNotFound) {
|
||||
<button
|
||||
mat-stroked-button
|
||||
(click)="checkOteStatus()"
|
||||
aria-label="Check OT&E account"
|
||||
[elementId]="getElementIdForOteBlock()"
|
||||
>
|
||||
Check OT&E Status
|
||||
</button>
|
||||
<button
|
||||
mat-flat-button
|
||||
color="primary"
|
||||
|
||||
@@ -18,6 +18,8 @@ import { MatChipInputEvent } from '@angular/material/chips';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { OteStatusComponent } from '../ote/oteStatus.component';
|
||||
import { RESTRICTED_ELEMENTS } from '../shared/directives/userLevelVisiblity.directive';
|
||||
import { Registrar, RegistrarService } from './registrar.service';
|
||||
import { RegistrarComponent, columns } from './registrarsTable.component';
|
||||
|
||||
@@ -70,6 +72,14 @@ export class RegistrarDetailsComponent implements OnInit {
|
||||
];
|
||||
}
|
||||
|
||||
checkOteStatus() {
|
||||
this.router.navigate([OteStatusComponent.PATH]);
|
||||
}
|
||||
|
||||
getElementIdForOteBlock() {
|
||||
return RESTRICTED_ELEMENTS.OTE;
|
||||
}
|
||||
|
||||
removeTLD(tld: string) {
|
||||
this.registrarInEdit.allowedTlds = this.registrarInEdit.allowedTlds?.filter(
|
||||
(v) => v != tld
|
||||
@@ -91,6 +101,6 @@ export class RegistrarDetailsComponent implements OnInit {
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.subscription.unsubscribe();
|
||||
this.subscription && this.subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { BackendService } from '../shared/services/backend.service';
|
||||
import { RegistrarSelectorComponent } from './registrarSelector.component';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
describe('RegistrarSelectorComponent', () => {
|
||||
let component: RegistrarSelectorComponent;
|
||||
@@ -28,7 +29,7 @@ describe('RegistrarSelectorComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [RegistrarSelectorComponent],
|
||||
imports: [MaterialModule, BrowserAnimationsModule],
|
||||
imports: [MaterialModule, BrowserAnimationsModule, FormsModule],
|
||||
providers: [
|
||||
BackendService,
|
||||
provideHttpClient(),
|
||||
|
||||
@@ -4,7 +4,17 @@
|
||||
<div class="console-app__registrars">
|
||||
<div class="console-app__registrars-header">
|
||||
<h1 class="mat-headline-4">Registrars</h1>
|
||||
<div class="spacer"></div>
|
||||
<button
|
||||
mat-stroked-button
|
||||
(click)="createOteAccount()"
|
||||
aria-label="Generate OT&E accounts"
|
||||
[elementId]="getElementIdForOteBlock()"
|
||||
>
|
||||
Create OT&E accounts
|
||||
</button>
|
||||
<button
|
||||
class="console-app__registrars-new"
|
||||
mat-flat-button
|
||||
color="primary"
|
||||
(click)="openNewRegistrar()"
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
min-width: $min-width !important;
|
||||
}
|
||||
|
||||
&__registrars-new {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
&__registrars-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@@ -17,6 +17,8 @@ import { MatPaginator } from '@angular/material/paginator';
|
||||
import { MatSort } from '@angular/material/sort';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { Router } from '@angular/router';
|
||||
import { NewOteComponent } from '../ote/newOte.component';
|
||||
import { RESTRICTED_ELEMENTS } from '../shared/directives/userLevelVisiblity.directive';
|
||||
import { Registrar, RegistrarService } from './registrar.service';
|
||||
|
||||
export const columns = [
|
||||
@@ -103,6 +105,14 @@ export class RegistrarComponent {
|
||||
this.dataSource.sort = this.sort;
|
||||
}
|
||||
|
||||
createOteAccount() {
|
||||
this.router.navigate([NewOteComponent.PATH]);
|
||||
}
|
||||
|
||||
getElementIdForOteBlock() {
|
||||
return RESTRICTED_ELEMENTS.OTE;
|
||||
}
|
||||
|
||||
openDetails(registrarId: string) {
|
||||
this.router.navigate(['registrars/', registrarId], {
|
||||
queryParamsHandling: 'merge',
|
||||
|
||||
@@ -20,20 +20,18 @@ import { FormsModule } from '@angular/forms';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { of } from 'rxjs';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
import {
|
||||
Registrar,
|
||||
RegistrarService,
|
||||
} from 'src/app/registrar/registrar.service';
|
||||
import { RegistrarService } from 'src/app/registrar/registrar.service';
|
||||
import { BackendService } from 'src/app/shared/services/backend.service';
|
||||
import SecurityComponent from './security.component';
|
||||
import { SecurityService, apiToUiConverter } from './security.service';
|
||||
import { SecurityService } from './security.service';
|
||||
import SecurityEditComponent from './securityEdit.component';
|
||||
import { MOCK_REGISTRAR_SERVICE } from 'src/testdata/registrar/registrar.service.mock';
|
||||
|
||||
describe('SecurityComponent', () => {
|
||||
let component: SecurityComponent;
|
||||
let fixture: ComponentFixture<SecurityComponent>;
|
||||
let fetchSecurityDetailsSpy: Function;
|
||||
let saveSpy: Function;
|
||||
let dummyRegistrarService: RegistrarService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const securityServiceSpy = jasmine.createSpyObj(SecurityService, [
|
||||
@@ -46,16 +44,13 @@ describe('SecurityComponent', () => {
|
||||
|
||||
saveSpy = securityServiceSpy.saveChanges;
|
||||
|
||||
dummyRegistrarService = {
|
||||
registrar: { ipAddressAllowList: ['123.123.123.123'] },
|
||||
} as RegistrarService;
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [SecurityComponent],
|
||||
declarations: [SecurityEditComponent, SecurityComponent],
|
||||
imports: [MaterialModule, BrowserAnimationsModule, FormsModule],
|
||||
providers: [
|
||||
BackendService,
|
||||
{ provide: RegistrarService, useValue: dummyRegistrarService },
|
||||
SecurityService,
|
||||
{ provide: RegistrarService, useValue: MOCK_REGISTRAR_SERVICE },
|
||||
provideHttpClient(),
|
||||
provideHttpClientTesting(),
|
||||
],
|
||||
@@ -78,78 +73,65 @@ describe('SecurityComponent', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render ip allow list', waitForAsync(() => {
|
||||
component.enableEdit();
|
||||
it('should render security elements', waitForAsync(() => {
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
expect(
|
||||
Array.from(
|
||||
fixture.nativeElement.querySelectorAll(
|
||||
'.settings-security__ip-allowlist'
|
||||
)
|
||||
)
|
||||
).toHaveSize(1);
|
||||
expect(
|
||||
fixture.nativeElement.querySelector('.settings-security__ip-allowlist')
|
||||
.value
|
||||
).toBe('123.123.123.123');
|
||||
let listElems: Array<HTMLElement> = Array.from(
|
||||
fixture.nativeElement.querySelectorAll('span.console-app__list-value')
|
||||
);
|
||||
expect(listElems).toHaveSize(8);
|
||||
expect(listElems.map((e) => e.textContent)).toEqual([
|
||||
'Change the password used for EPP logins',
|
||||
'••••••••••••••',
|
||||
'Restrict access to EPP production servers to the following IP/IPv6 addresses, or ranges like 1.1.1.0/24',
|
||||
'123.123.123.123',
|
||||
'X.509 PEM certificate for EPP production access',
|
||||
'No client certificate on file.',
|
||||
'X.509 PEM backup certificate for EPP production access',
|
||||
'No failover certificate on file.',
|
||||
]);
|
||||
});
|
||||
}));
|
||||
|
||||
it('should remove ip', waitForAsync(() => {
|
||||
expect(
|
||||
Array.from(
|
||||
fixture.nativeElement.querySelectorAll(
|
||||
'.settings-security__ip-allowlist'
|
||||
)
|
||||
)
|
||||
).toHaveSize(1);
|
||||
component.removeIpEntry(0);
|
||||
component.dataSource.ipAddressAllowList =
|
||||
component.dataSource.ipAddressAllowList?.splice(1);
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(
|
||||
Array.from(
|
||||
fixture.nativeElement.querySelectorAll(
|
||||
'.settings-security__ip-allowlist'
|
||||
)
|
||||
)
|
||||
).toHaveSize(0);
|
||||
let listElems: Array<HTMLElement> = Array.from(
|
||||
fixture.nativeElement.querySelectorAll('span.console-app__list-value')
|
||||
);
|
||||
expect(listElems.map((e) => e.textContent)).toContain(
|
||||
'No IP addresses on file.'
|
||||
);
|
||||
});
|
||||
}));
|
||||
|
||||
it('should toggle inEdit', () => {
|
||||
expect(component.inEdit).toBeFalse();
|
||||
component.enableEdit();
|
||||
expect(component.inEdit).toBeTrue();
|
||||
it('should toggle isEditingSecurity', () => {
|
||||
expect(component.securityService.isEditingSecurity).toBeFalse();
|
||||
component.editSecurity();
|
||||
expect(component.securityService.isEditingSecurity).toBeTrue();
|
||||
});
|
||||
|
||||
it('should create temporary data structure', () => {
|
||||
expect(component.dataSource).toEqual(
|
||||
apiToUiConverter(dummyRegistrarService.registrar)
|
||||
);
|
||||
component.removeIpEntry(0);
|
||||
expect(component.dataSource).toEqual({ ipAddressAllowList: [] });
|
||||
expect(dummyRegistrarService.registrar).toEqual({
|
||||
ipAddressAllowList: ['123.123.123.123'],
|
||||
} as Registrar);
|
||||
component.cancel();
|
||||
expect(component.dataSource).toEqual(
|
||||
apiToUiConverter(dummyRegistrarService.registrar)
|
||||
);
|
||||
it('should toggle isEditingPassword', () => {
|
||||
expect(component.securityService.isEditingPassword).toBeFalse();
|
||||
component.editEppPassword();
|
||||
expect(component.securityService.isEditingPassword).toBeTrue();
|
||||
});
|
||||
|
||||
it('should call save', waitForAsync(async () => {
|
||||
component.enableEdit();
|
||||
fixture.detectChanges();
|
||||
component.editSecurity();
|
||||
await fixture.whenStable();
|
||||
fixture.detectChanges();
|
||||
const el = fixture.nativeElement.querySelector(
|
||||
'.settings-security__clientCertificate'
|
||||
'.console-app__clientCertificateValue'
|
||||
);
|
||||
el.value = 'test';
|
||||
el.dispatchEvent(new Event('input'));
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
fixture.nativeElement
|
||||
.querySelector('.settings-security__actions-save')
|
||||
.querySelector('.settings-security__edit-save')
|
||||
.click();
|
||||
expect(saveSpy).toHaveBeenCalledOnceWith({
|
||||
ipAddressAllowList: [{ value: '123.123.123.123' }],
|
||||
|
||||
@@ -35,6 +35,7 @@ export default class SecurityComponent {
|
||||
if (this.registrarService.registrar()) {
|
||||
this.dataSource = apiToUiConverter(this.registrarService.registrar());
|
||||
this.securityService.isEditingSecurity = false;
|
||||
this.securityService.isEditingPassword = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -21,11 +21,13 @@ import { BackendService } from 'src/app/shared/services/backend.service';
|
||||
import SecurityComponent from './security.component';
|
||||
import {
|
||||
SecurityService,
|
||||
SecuritySettings,
|
||||
SecuritySettingsBackendModel,
|
||||
apiToUiConverter,
|
||||
uiToApiConverter,
|
||||
} from './security.service';
|
||||
import {
|
||||
SecuritySettings,
|
||||
SecuritySettingsBackendModel,
|
||||
} from 'src/app/registrar/registrar.service';
|
||||
|
||||
describe('SecurityService', () => {
|
||||
const uiMockData: SecuritySettings = {
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
<p>X.509 PEM certificate for EPP production access.</p>
|
||||
<mat-form-field appearance="outline">
|
||||
<textarea
|
||||
class="console-app__clientCertificateValue"
|
||||
matInput
|
||||
[(ngModel)]="dataSource.clientCertificate"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
|
||||
@@ -32,7 +32,14 @@ describe('WhoisComponent', () => {
|
||||
imports: [MaterialModule, BrowserAnimationsModule],
|
||||
providers: [
|
||||
BackendService,
|
||||
{ provide: RegistrarService, useValue: { registrar: {} } },
|
||||
{
|
||||
provide: RegistrarService,
|
||||
useValue: {
|
||||
registrar: function () {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
},
|
||||
provideHttpClient(),
|
||||
provideHttpClientTesting(),
|
||||
],
|
||||
|
||||
@@ -17,10 +17,11 @@ import { UserDataService } from '../services/userData.service';
|
||||
|
||||
export enum RESTRICTED_ELEMENTS {
|
||||
REGISTRAR_ELEMENT,
|
||||
OTE,
|
||||
}
|
||||
|
||||
export const DISABLED_ELEMENTS_PER_ROLE = {
|
||||
NONE: [RESTRICTED_ELEMENTS.REGISTRAR_ELEMENT],
|
||||
NONE: [RESTRICTED_ELEMENTS.REGISTRAR_ELEMENT, RESTRICTED_ELEMENTS.OTE],
|
||||
};
|
||||
|
||||
@Directive({
|
||||
|
||||
@@ -19,6 +19,8 @@ import { Observable, catchError, of, throwError } from 'rxjs';
|
||||
import { DomainListResult } from 'src/app/domains/domainList.service';
|
||||
import { DomainLocksResult } from 'src/app/domains/registryLock.service';
|
||||
import { RegistryLockVerificationResponse } from 'src/app/lock/registryLockVerify.service';
|
||||
import { OteCreateResponse } from 'src/app/ote/newOte.component';
|
||||
import { OteStatusResponse } from 'src/app/ote/oteStatus.component';
|
||||
import {
|
||||
Registrar,
|
||||
SecuritySettingsBackendModel,
|
||||
@@ -198,6 +200,22 @@ export class BackendService {
|
||||
.pipe(catchError((err) => this.errorCatcher<DomainLocksResult[]>(err)));
|
||||
}
|
||||
|
||||
generateOte(
|
||||
oteForm: Object,
|
||||
registrarId: string
|
||||
): Observable<OteCreateResponse> {
|
||||
return this.http.post<OteCreateResponse>(
|
||||
`/console-api/ote?registrarId=${registrarId}`,
|
||||
oteForm
|
||||
);
|
||||
}
|
||||
|
||||
getOteStatus(registrarId: string) {
|
||||
return this.http
|
||||
.get<OteStatusResponse[]>(`/console-api/ote?registrarId=${registrarId}`)
|
||||
.pipe(catchError((err) => this.errorCatcher<OteStatusResponse[]>(err)));
|
||||
}
|
||||
|
||||
verifyRegistryLockRequest(
|
||||
lockVerificationCode: string
|
||||
): Observable<RegistryLockVerificationResponse> {
|
||||
|
||||
21
console-webapp/src/testdata/registrar/registrar.service.mock.ts
vendored
Normal file
21
console-webapp/src/testdata/registrar/registrar.service.mock.ts
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2024 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { RegistrarService } from 'src/app/registrar/registrar.service';
|
||||
|
||||
export const MOCK_REGISTRAR_SERVICE = {
|
||||
registrar: function () {
|
||||
return { ipAddressAllowList: ['123.123.123.123'] };
|
||||
},
|
||||
} as RegistrarService;
|
||||
@@ -29,5 +29,6 @@
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"strictTemplates": true
|
||||
}
|
||||
},
|
||||
"exclude": ["./src/testdata/*.*/*.ts"]
|
||||
}
|
||||
|
||||
@@ -119,6 +119,18 @@ public final class RegistryConfig {
|
||||
return config.gcpProject.projectIdNumber;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("backendServiceIds")
|
||||
public static Map<String, Long> provideBackendServiceIds(RegistryConfigSettings config) {
|
||||
return config.gcpProject.backendServiceIds;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("baseDomain")
|
||||
public static String provideBaseDomain(RegistryConfigSettings config) {
|
||||
return config.gcpProject.baseDomain;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("locationId")
|
||||
public static String provideLocationId(RegistryConfigSettings config) {
|
||||
@@ -1259,12 +1271,6 @@ public final class RegistryConfig {
|
||||
return config.auth.oauthClientId;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("fallbackOauthClientId")
|
||||
public static String provideFallbackOauthClientId(RegistryConfigSettings config) {
|
||||
return config.auth.fallbackOauthClientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the OAuth scopes required for accessing Google APIs using the default credential.
|
||||
*/
|
||||
|
||||
@@ -56,13 +56,14 @@ public class RegistryConfigSettings {
|
||||
public String bsaServiceUrl;
|
||||
public String toolsServiceUrl;
|
||||
public String pubapiServiceUrl;
|
||||
public Map<String, Long> backendServiceIds;
|
||||
public String baseDomain;
|
||||
}
|
||||
|
||||
/** Configuration options for authenticating users. */
|
||||
public static class Auth {
|
||||
public List<String> allowedServiceAccountEmails;
|
||||
public String oauthClientId;
|
||||
public String fallbackOauthClientId;
|
||||
}
|
||||
|
||||
/** Configuration options for accessing Google APIs. */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# This is the default configuration file for Nomulus. Do not make changes to it
|
||||
# unless you are writing new features that requires you to. To customize an
|
||||
# unless you are writing new features that require you to. To customize an
|
||||
# individual deployment or environment, create a nomulus-config.yaml file in the
|
||||
# WEB-INF/ directory overriding only the values you wish to change. You may need
|
||||
# to override some of these values to configure and enable some services used in
|
||||
@@ -24,6 +24,17 @@ gcpProject:
|
||||
toolsServiceUrl: https://tools.example.com
|
||||
pubapiServiceUrl: https://pubapi.example.com
|
||||
|
||||
# The backend service IDs created when setting up GKE routes. They will be included in the
|
||||
# audience field in the JWT that IAP creates.
|
||||
# See: https://cloud.google.com/iap/docs/signed-headers-howto#verifying_the_jwt_payload
|
||||
backendServiceIds:
|
||||
frontend: 12345
|
||||
backend: 12345
|
||||
pubapi: 12345
|
||||
console: 12345
|
||||
|
||||
# The base domain name of the registry service. Services are reachable at [service].baseDomain.
|
||||
baseDomain: registry.test
|
||||
|
||||
gSuite:
|
||||
# Publicly accessible domain name of the running G Suite instance.
|
||||
@@ -328,25 +339,21 @@ caching:
|
||||
# Note: Only allowedServiceAccountEmails and oauthClientId should be configured.
|
||||
# Other fields are related to OAuth-based authentication and will be removed.
|
||||
auth:
|
||||
# Service accounts (e.g. default service account, account used by Cloud
|
||||
# Service accounts (e.g., default service account, account used by Cloud
|
||||
# Scheduler) allowed to send authenticated requests.
|
||||
allowedServiceAccountEmails:
|
||||
- default-service-account-email@email.com
|
||||
- cloud-scheduler-email@email.com
|
||||
|
||||
# OAuth 2.0 client ID that will be used as the audience in OIDC ID tokens sent
|
||||
# from clients (e.g. proxy, nomulus tool, cloud tasks) for authentication. The
|
||||
# from clients (e.g., proxy, nomulus tool, cloud tasks) for authentication. The
|
||||
# same ID is the only one accepted by the regular OIDC or IAP authentication
|
||||
# mechanisms. In most cases we should use the client ID created for IAP here,
|
||||
# mechanisms. In most cases, we should use the client ID created for IAP here,
|
||||
# as it allows requests bearing a token with this audience to be accepted by
|
||||
# both IAP or regular OIDC. The clientId value in proxy config file should be
|
||||
# the same as this one.
|
||||
oauthClientId: iap-oauth-clientid
|
||||
|
||||
# Same as above, but serve as a fallback, so we can switch the client ID of
|
||||
# the proxy without downtime.
|
||||
fallbackOauthClientId: fallback-oauth-clientid
|
||||
|
||||
credentialOAuth:
|
||||
# OAuth scopes required for accessing Google APIs using the default
|
||||
# credential.
|
||||
|
||||
@@ -36,7 +36,7 @@ import javax.inject.Inject;
|
||||
/** Action that manually triggers refresh of DNS information. */
|
||||
@Action(
|
||||
service = Action.Service.BACKEND,
|
||||
path = "/_dr/dnsRefresh",
|
||||
path = "/_dr/task/dnsRefresh",
|
||||
automaticallyPrintOk = true,
|
||||
auth = Auth.AUTH_ADMIN)
|
||||
public final class RefreshDnsAction implements Runnable {
|
||||
|
||||
@@ -165,7 +165,7 @@
|
||||
<!-- Manually refreshes DNS information. -->
|
||||
<servlet-mapping>
|
||||
<servlet-name>backend-servlet</servlet-name>
|
||||
<url-pattern>/_dr/dnsRefresh</url-pattern>
|
||||
<url-pattern>/_dr/task/dnsRefresh</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Fans out a cron task over an adjustable range of TLDs. -->
|
||||
|
||||
@@ -233,6 +233,7 @@ public class RegistrarBase extends UpdateAutoTimestampEntity implements Buildabl
|
||||
String registrarName;
|
||||
|
||||
/** The type of this registrar. */
|
||||
@Expose
|
||||
@Column(nullable = false)
|
||||
@Enumerated(EnumType.STRING)
|
||||
Type type;
|
||||
|
||||
@@ -102,9 +102,11 @@ interface RegistryComponent {
|
||||
class RegistryModule {
|
||||
@Provides
|
||||
static RequestHandler<RequestComponent> provideRequestHandler(
|
||||
@Config("baseDomain") String baseDomain,
|
||||
Provider<RequestComponent.Builder> componentProvider,
|
||||
RequestAuthenticator requestAuthenticator) {
|
||||
return RequestHandler.create(RequestComponent.class, componentProvider, requestAuthenticator);
|
||||
return RequestHandler.create(
|
||||
RequestComponent.class, baseDomain, componentProvider, requestAuthenticator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,6 +113,8 @@ import google.registry.ui.server.console.ConsoleDomainGetAction;
|
||||
import google.registry.ui.server.console.ConsoleDomainListAction;
|
||||
import google.registry.ui.server.console.ConsoleDumDownloadAction;
|
||||
import google.registry.ui.server.console.ConsoleEppPasswordAction;
|
||||
import google.registry.ui.server.console.ConsoleModule;
|
||||
import google.registry.ui.server.console.ConsoleOteAction;
|
||||
import google.registry.ui.server.console.ConsoleRegistryLockAction;
|
||||
import google.registry.ui.server.console.ConsoleRegistryLockVerifyAction;
|
||||
import google.registry.ui.server.console.ConsoleUpdateRegistrarAction;
|
||||
@@ -121,15 +123,6 @@ import google.registry.ui.server.console.RegistrarsAction;
|
||||
import google.registry.ui.server.console.settings.ContactAction;
|
||||
import google.registry.ui.server.console.settings.SecurityAction;
|
||||
import google.registry.ui.server.console.settings.WhoisRegistrarFieldsAction;
|
||||
import google.registry.ui.server.registrar.ConsoleOteSetupAction;
|
||||
import google.registry.ui.server.registrar.ConsoleRegistrarCreatorAction;
|
||||
import google.registry.ui.server.registrar.ConsoleUiAction;
|
||||
import google.registry.ui.server.registrar.OteStatusAction;
|
||||
import google.registry.ui.server.registrar.RegistrarConsoleModule;
|
||||
import google.registry.ui.server.registrar.RegistrarSettingsAction;
|
||||
import google.registry.ui.server.registrar.RegistryLockGetAction;
|
||||
import google.registry.ui.server.registrar.RegistryLockPostAction;
|
||||
import google.registry.ui.server.registrar.RegistryLockVerifyAction;
|
||||
import google.registry.whois.WhoisAction;
|
||||
import google.registry.whois.WhoisHttpAction;
|
||||
import google.registry.whois.WhoisModule;
|
||||
@@ -142,6 +135,7 @@ import google.registry.whois.WhoisModule;
|
||||
BillingModule.class,
|
||||
CheckApiModule.class,
|
||||
CloudDnsWriterModule.class,
|
||||
ConsoleModule.class,
|
||||
CronModule.class,
|
||||
CustomLogicModule.class,
|
||||
DnsCountQueryCoordinatorModule.class,
|
||||
@@ -154,7 +148,6 @@ import google.registry.whois.WhoisModule;
|
||||
LoadTestModule.class,
|
||||
RdapModule.class,
|
||||
RdeModule.class,
|
||||
RegistrarConsoleModule.class,
|
||||
ReportingModule.class,
|
||||
RequestModule.class,
|
||||
SheetModule.class,
|
||||
@@ -186,16 +179,12 @@ interface RequestComponent {
|
||||
|
||||
ConsoleEppPasswordAction consoleEppPasswordAction();
|
||||
|
||||
ConsoleOteSetupAction consoleOteSetupAction();
|
||||
|
||||
ConsoleRegistrarCreatorAction consoleRegistrarCreatorAction();
|
||||
ConsoleOteAction consoleOteAction();
|
||||
|
||||
ConsoleRegistryLockAction consoleRegistryLockAction();
|
||||
|
||||
ConsoleRegistryLockVerifyAction consoleRegistryLockVerifyAction();
|
||||
|
||||
ConsoleUiAction consoleUiAction();
|
||||
|
||||
ConsoleUpdateRegistrarAction consoleUpdateRegistrarAction();
|
||||
|
||||
ConsoleUserDataAction consoleUserDataAction();
|
||||
@@ -254,8 +243,6 @@ interface RequestComponent {
|
||||
|
||||
NordnVerifyAction nordnVerifyAction();
|
||||
|
||||
OteStatusAction oteStatusAction();
|
||||
|
||||
PublishDnsUpdatesAction publishDnsUpdatesAction();
|
||||
|
||||
PublishInvoicesAction uploadInvoicesAction();
|
||||
@@ -296,16 +283,8 @@ interface RequestComponent {
|
||||
|
||||
RefreshDnsOnHostRenameAction refreshDnsOnHostRenameAction();
|
||||
|
||||
RegistrarSettingsAction registrarSettingsAction();
|
||||
|
||||
RegistrarsAction registrarsAction();
|
||||
|
||||
RegistryLockGetAction registryLockGetAction();
|
||||
|
||||
RegistryLockPostAction registryLockPostAction();
|
||||
|
||||
RegistryLockVerifyAction registryLockVerifyAction();
|
||||
|
||||
RelockDomainAction relockDomainAction();
|
||||
|
||||
ResaveAllEppResourcesPipelineAction resaveAllEppResourcesPipelineAction();
|
||||
|
||||
@@ -29,6 +29,8 @@ import google.registry.ui.server.console.ConsoleDomainGetAction;
|
||||
import google.registry.ui.server.console.ConsoleDomainListAction;
|
||||
import google.registry.ui.server.console.ConsoleDumDownloadAction;
|
||||
import google.registry.ui.server.console.ConsoleEppPasswordAction;
|
||||
import google.registry.ui.server.console.ConsoleModule;
|
||||
import google.registry.ui.server.console.ConsoleOteAction;
|
||||
import google.registry.ui.server.console.ConsoleRegistryLockAction;
|
||||
import google.registry.ui.server.console.ConsoleRegistryLockVerifyAction;
|
||||
import google.registry.ui.server.console.ConsoleUpdateRegistrarAction;
|
||||
@@ -41,7 +43,6 @@ import google.registry.ui.server.registrar.ConsoleOteSetupAction;
|
||||
import google.registry.ui.server.registrar.ConsoleRegistrarCreatorAction;
|
||||
import google.registry.ui.server.registrar.ConsoleUiAction;
|
||||
import google.registry.ui.server.registrar.OteStatusAction;
|
||||
import google.registry.ui.server.registrar.RegistrarConsoleModule;
|
||||
import google.registry.ui.server.registrar.RegistrarSettingsAction;
|
||||
import google.registry.ui.server.registrar.RegistryLockGetAction;
|
||||
import google.registry.ui.server.registrar.RegistryLockPostAction;
|
||||
@@ -54,7 +55,7 @@ import google.registry.ui.server.registrar.RegistryLockVerifyAction;
|
||||
BatchModule.class,
|
||||
DnsModule.class,
|
||||
EppTlsModule.class,
|
||||
RegistrarConsoleModule.class,
|
||||
ConsoleModule.class,
|
||||
RequestModule.class,
|
||||
WhiteboxModule.class,
|
||||
})
|
||||
@@ -65,6 +66,8 @@ public interface FrontendRequestComponent {
|
||||
|
||||
ConsoleEppPasswordAction consoleEppPasswordAction();
|
||||
|
||||
ConsoleOteAction consoleOteAction();
|
||||
|
||||
ConsoleOteSetupAction consoleOteSetupAction();
|
||||
ConsoleRegistrarCreatorAction consoleRegistrarCreatorAction();
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
package google.registry.request;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import google.registry.request.auth.Auth;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -36,7 +38,6 @@ public @interface Action {
|
||||
BACKEND("backend"),
|
||||
PUBAPI("pubapi");
|
||||
|
||||
|
||||
private final String serviceId;
|
||||
|
||||
Service(String serviceId) {
|
||||
@@ -49,9 +50,33 @@ public @interface Action {
|
||||
}
|
||||
}
|
||||
|
||||
enum GkeService {
|
||||
// This designation means that it defers to the GAE service, so we don't have to annotate EVERY
|
||||
// action during the GKE migration.
|
||||
SAME_AS_GAE("same_as_gae"),
|
||||
FRONTEND("frontend"),
|
||||
BACKEND("backend"),
|
||||
PUBAPI("pubapi"),
|
||||
CONSOLE("console");
|
||||
|
||||
private final String serviceId;
|
||||
|
||||
GkeService(String serviceId) {
|
||||
this.serviceId = serviceId;
|
||||
}
|
||||
|
||||
public String getServiceId() {
|
||||
checkState(this != SAME_AS_GAE, "Cannot get service Id for SAME_AS_GAE");
|
||||
return serviceId;
|
||||
}
|
||||
}
|
||||
|
||||
/** Which App Engine service this action lives on. */
|
||||
Service service();
|
||||
|
||||
/** Which GKE service this action lives on. */
|
||||
GkeService gkeService() default GkeService.SAME_AS_GAE;
|
||||
|
||||
/** HTTP path to serve the action from. The path components must be percent-escaped. */
|
||||
String path();
|
||||
|
||||
@@ -72,4 +97,22 @@ public @interface Action {
|
||||
|
||||
/** Authentication settings. */
|
||||
Auth auth();
|
||||
|
||||
// TODO(jianglai): Use Action.gkeService() directly once we are off GAE.
|
||||
class ServiceGetter {
|
||||
public static GkeService get(Action action) {
|
||||
GkeService service = action.gkeService();
|
||||
if (service != GkeService.SAME_AS_GAE) {
|
||||
return service;
|
||||
}
|
||||
Service gaeService = action.service();
|
||||
return switch (gaeService) {
|
||||
case DEFAULT -> GkeService.FRONTEND;
|
||||
case BACKEND -> GkeService.BACKEND;
|
||||
case TOOLS -> GkeService.BACKEND;
|
||||
case BSA -> GkeService.BACKEND;
|
||||
case PUBAPI -> GkeService.PUBAPI;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,14 +22,17 @@ import static jakarta.servlet.http.HttpServletResponse.SC_METHOD_NOT_ALLOWED;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_NOT_FOUND;
|
||||
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.request.Action.GkeService;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.request.auth.RequestAuthenticator;
|
||||
import google.registry.util.NonFinalForTesting;
|
||||
import google.registry.util.RegistryEnvironment;
|
||||
import google.registry.util.SystemClock;
|
||||
import google.registry.util.TypeUtils.TypeInstantiator;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Provider;
|
||||
@@ -69,6 +72,7 @@ public class RequestHandler<C> {
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private final Router router;
|
||||
@Nullable private final String baseDomain;
|
||||
private final Provider<? extends RequestComponentBuilder<C>> requestComponentBuilderProvider;
|
||||
private final RequestAuthenticator requestAuthenticator;
|
||||
private final SystemClock clock = new SystemClock();
|
||||
@@ -91,22 +95,22 @@ public class RequestHandler<C> {
|
||||
protected RequestHandler(
|
||||
Provider<? extends RequestComponentBuilder<C>> requestComponentBuilderProvider,
|
||||
RequestAuthenticator requestAuthenticator) {
|
||||
this(null, requestComponentBuilderProvider, requestAuthenticator);
|
||||
this(null, null, requestComponentBuilderProvider, requestAuthenticator);
|
||||
}
|
||||
|
||||
/** Creates a new RequestHandler with an explicit component class for test purposes. */
|
||||
public static <C> RequestHandler<C> create(
|
||||
Class<C> component,
|
||||
@Nullable String baseDomain,
|
||||
Provider<? extends RequestComponentBuilder<C>> requestComponentBuilderProvider,
|
||||
RequestAuthenticator requestAuthenticator) {
|
||||
return new RequestHandler<>(
|
||||
checkNotNull(component),
|
||||
requestComponentBuilderProvider,
|
||||
requestAuthenticator);
|
||||
checkNotNull(component), baseDomain, requestComponentBuilderProvider, requestAuthenticator);
|
||||
}
|
||||
|
||||
private RequestHandler(
|
||||
@Nullable Class<C> component,
|
||||
@Nullable String baseDomain,
|
||||
Provider<? extends RequestComponentBuilder<C>> requestComponentBuilderProvider,
|
||||
RequestAuthenticator requestAuthenticator) {
|
||||
// If the component class isn't explicitly provided, infer it from the class's own typing.
|
||||
@@ -114,6 +118,7 @@ public class RequestHandler<C> {
|
||||
// preserved at runtime, so only expose that option via the protected constructor.
|
||||
this.router = Router.create(
|
||||
component != null ? component : new TypeInstantiator<C>(getClass()){}.getExactType());
|
||||
this.baseDomain = baseDomain;
|
||||
this.requestComponentBuilderProvider = checkNotNull(requestComponentBuilderProvider);
|
||||
this.requestAuthenticator = checkNotNull(requestAuthenticator);
|
||||
}
|
||||
@@ -137,6 +142,17 @@ public class RequestHandler<C> {
|
||||
rsp.sendError(SC_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
if (RegistryEnvironment.isOnJetty()) {
|
||||
GkeService service = Action.ServiceGetter.get(route.get().action());
|
||||
String expectedDomain = String.format("%s.%s", service.getServiceId(), baseDomain);
|
||||
String actualDomain = req.getServerName();
|
||||
if (!Objects.equals(actualDomain, expectedDomain)) {
|
||||
logger.atWarning().log(
|
||||
"Actual domain %s does not match expected domain %s", actualDomain, expectedDomain);
|
||||
rsp.sendError(SC_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!route.get().isMethodAllowed(method)) {
|
||||
logger.atWarning().log("Method %s not allowed for: %s", method, path);
|
||||
rsp.sendError(SC_METHOD_NOT_ALLOWED);
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Streams;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -37,6 +38,7 @@ import java.util.Map;
|
||||
* the content to be displayed. The columns are:
|
||||
*
|
||||
* <ol>
|
||||
* <li>the GKE service this action lives on
|
||||
* <li>the URL path which maps to this action (with a "(*)" after it if the prefix flag is set)
|
||||
* <li>the simple name of the action class
|
||||
* <li>the allowable HTTP methods
|
||||
@@ -49,12 +51,13 @@ import java.util.Map;
|
||||
*/
|
||||
public class RouterDisplayHelper {
|
||||
|
||||
private static final String SERVICE = "service";
|
||||
private static final String PATH = "path";
|
||||
private static final String CLASS = "class";
|
||||
private static final String METHODS = "methods";
|
||||
private static final String MINIMUM_LEVEL = "minLevel";
|
||||
|
||||
private static final String FORMAT = "%%-%ds %%-%ds %%-%ds %%-2s %%-%ds %%s";
|
||||
private static final String FORMAT = "%%-%ds %%-%ds %%-%ds %%-%ds %%-2s %%-%ds %%s";
|
||||
|
||||
/** Returns a string representation of the routing map in the specified component. */
|
||||
public static String extractHumanReadableRoutesFromComponent(Class<?> componentClass) {
|
||||
@@ -76,6 +79,7 @@ public class RouterDisplayHelper {
|
||||
private static String getFormatString(Map<String, Integer> columnWidths) {
|
||||
return String.format(
|
||||
FORMAT,
|
||||
columnWidths.get(SERVICE),
|
||||
columnWidths.get(PATH),
|
||||
columnWidths.get(CLASS),
|
||||
columnWidths.get(METHODS),
|
||||
@@ -84,18 +88,13 @@ public class RouterDisplayHelper {
|
||||
|
||||
private static String headerToString(String formatString) {
|
||||
return String.format(
|
||||
formatString,
|
||||
"PATH",
|
||||
"CLASS",
|
||||
"METHODS",
|
||||
"OK",
|
||||
"MIN",
|
||||
"USER_POLICY");
|
||||
formatString, "SERVICE", "PATH", "CLASS", "METHODS", "OK", "MIN", "USER_POLICY");
|
||||
}
|
||||
|
||||
private static String routeToString(Route route, String formatString) {
|
||||
return String.format(
|
||||
formatString,
|
||||
Action.ServiceGetter.get(route.action()).name(),
|
||||
route.action().isPrefix() ? (route.action().path() + "(*)") : route.action().path(),
|
||||
route.actionClass().getSimpleName(),
|
||||
Joiner.on(",").join(route.action().method()),
|
||||
@@ -107,12 +106,17 @@ public class RouterDisplayHelper {
|
||||
private static String formatRoutes(Iterable<Route> routes) {
|
||||
|
||||
// Use the column header length as a minimum.
|
||||
int serviceWidth = 7;
|
||||
int pathWidth = 4;
|
||||
int classWidth = 5;
|
||||
int methodsWidth = 7;
|
||||
int minLevelWidth = 3;
|
||||
for (Route route : routes) {
|
||||
int len =
|
||||
int len = Action.ServiceGetter.get(route.action()).name().length();
|
||||
if (len > serviceWidth) {
|
||||
serviceWidth = len;
|
||||
}
|
||||
len =
|
||||
route.action().isPrefix()
|
||||
? (route.action().path().length() + 3)
|
||||
: route.action().path().length();
|
||||
@@ -135,6 +139,7 @@ public class RouterDisplayHelper {
|
||||
final String formatString =
|
||||
getFormatString(
|
||||
new ImmutableMap.Builder<String, Integer>()
|
||||
.put(SERVICE, serviceWidth)
|
||||
.put(PATH, pathWidth)
|
||||
.put(CLASS, classWidth)
|
||||
.put(METHODS, methodsWidth)
|
||||
@@ -143,6 +148,9 @@ public class RouterDisplayHelper {
|
||||
return headerToString(formatString)
|
||||
+ String.format("%n")
|
||||
+ Streams.stream(routes)
|
||||
.sorted(
|
||||
Comparator.comparing(
|
||||
(Route route) -> Action.ServiceGetter.get(route.action()).ordinal()))
|
||||
.map(route -> routeToString(route, formatString))
|
||||
.collect(joining(String.format("%n")));
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ package google.registry.request.auth;
|
||||
|
||||
import static com.google.common.net.HttpHeaders.AUTHORIZATION;
|
||||
|
||||
import com.google.auth.oauth2.TokenVerifier;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
@@ -24,6 +23,10 @@ import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.request.auth.OidcTokenAuthenticationMechanism.IapOidcAuthenticationMechanism;
|
||||
import google.registry.request.auth.OidcTokenAuthenticationMechanism.RegularOidcAuthenticationMechanism;
|
||||
import google.registry.request.auth.OidcTokenAuthenticationMechanism.TokenExtractor;
|
||||
import google.registry.request.auth.OidcTokenAuthenticationMechanism.TokenVerifier;
|
||||
import google.registry.util.RegistryEnvironment;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Qualifier;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
@@ -35,9 +38,10 @@ public class AuthModule {
|
||||
// See https://cloud.google.com/iap/docs/signed-headers-howto#securing_iap_headers.
|
||||
public static final String IAP_HEADER_NAME = "X-Goog-IAP-JWT-Assertion";
|
||||
public static final String BEARER_PREFIX = "Bearer ";
|
||||
// TODO: Change the IAP audience format once we are on GKE.
|
||||
// TODO (jianglai): Only use GKE audience once we are fully migrated to GKE.
|
||||
// See: https://cloud.google.com/iap/docs/signed-headers-howto#verifying_the_jwt_payload
|
||||
private static final String IAP_AUDIENCE_FORMAT = "/projects/%d/apps/%s";
|
||||
private static final String IAP_GAE_AUDIENCE_FORMAT = "/projects/%d/apps/%s";
|
||||
private static final String IAP_GKE_AUDIENCE_FORMAT = "/projects/%d/global/backendServices/%d";
|
||||
private static final String IAP_ISSUER_URL = "https://cloud.google.com/iap";
|
||||
private static final String REGULAR_ISSUER_URL = "https://accounts.google.com";
|
||||
|
||||
@@ -62,24 +66,35 @@ public class AuthModule {
|
||||
@IapOidc
|
||||
@Singleton
|
||||
TokenVerifier provideIapTokenVerifier(
|
||||
@Config("projectId") String projectId, @Config("projectIdNumber") long projectIdNumber) {
|
||||
String audience = String.format(IAP_AUDIENCE_FORMAT, projectIdNumber, projectId);
|
||||
return TokenVerifier.newBuilder().setAudience(audience).setIssuer(IAP_ISSUER_URL).build();
|
||||
@Config("projectId") String projectId,
|
||||
@Config("projectIdNumber") long projectIdNumber,
|
||||
@Config("backendServiceIds") Map<String, Long> backendServiceIds) {
|
||||
com.google.auth.oauth2.TokenVerifier.Builder tokenVerifierBuilder =
|
||||
com.google.auth.oauth2.TokenVerifier.newBuilder().setIssuer(IAP_ISSUER_URL);
|
||||
return (String service, String token) -> {
|
||||
String audience;
|
||||
if (RegistryEnvironment.isOnJetty()) {
|
||||
long backendServiceId = backendServiceIds.get(service);
|
||||
audience = String.format(IAP_GKE_AUDIENCE_FORMAT, projectIdNumber, backendServiceId);
|
||||
} else {
|
||||
audience = String.format(IAP_GAE_AUDIENCE_FORMAT, projectIdNumber, projectId);
|
||||
}
|
||||
return tokenVerifierBuilder.setAudience(audience).build().verify(token);
|
||||
};
|
||||
}
|
||||
|
||||
@Provides
|
||||
@RegularOidc
|
||||
@Singleton
|
||||
TokenVerifier provideRegularTokenVerifier(@Config("oauthClientId") String clientId) {
|
||||
return TokenVerifier.newBuilder().setAudience(clientId).setIssuer(REGULAR_ISSUER_URL).build();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@RegularOidcFallback
|
||||
@Singleton
|
||||
TokenVerifier provideFallbackRegularTokenVerifier(
|
||||
@Config("fallbackOauthClientId") String clientId) {
|
||||
return TokenVerifier.newBuilder().setAudience(clientId).setIssuer(REGULAR_ISSUER_URL).build();
|
||||
com.google.auth.oauth2.TokenVerifier tokenVerifier =
|
||||
com.google.auth.oauth2.TokenVerifier.newBuilder()
|
||||
.setAudience(clientId)
|
||||
.setIssuer(REGULAR_ISSUER_URL)
|
||||
.build();
|
||||
return (@Nullable String service, String token) -> {
|
||||
return tokenVerifier.verify(token);
|
||||
};
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -18,8 +18,9 @@ import static com.google.common.base.Preconditions.checkState;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
|
||||
import com.google.api.client.json.webtoken.JsonWebSignature;
|
||||
import com.google.auth.oauth2.TokenVerifier;
|
||||
import com.google.auth.oauth2.TokenVerifier.VerificationException;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
@@ -27,7 +28,6 @@ import google.registry.model.console.User;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.request.auth.AuthModule.IapOidc;
|
||||
import google.registry.request.auth.AuthModule.RegularOidc;
|
||||
import google.registry.request.auth.AuthModule.RegularOidcFallback;
|
||||
import google.registry.request.auth.AuthSettings.AuthLevel;
|
||||
import google.registry.util.RegistryEnvironment;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
@@ -51,27 +51,23 @@ public abstract class OidcTokenAuthenticationMechanism implements Authentication
|
||||
|
||||
public static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
// A workaround that allows "use" of the OIDC authenticator when running local testing, i.e.
|
||||
// A workaround that allows "use" of the OIDC authenticator when running local testing, i.e.,
|
||||
// the RegistryTestServer
|
||||
private static AuthResult authResultForTesting = null;
|
||||
|
||||
protected final TokenVerifier tokenVerifier;
|
||||
|
||||
protected final Optional<TokenVerifier> fallbackTokenVerifier;
|
||||
|
||||
protected final TokenExtractor tokenExtractor;
|
||||
|
||||
protected final TokenVerifier tokenVerifier;
|
||||
|
||||
private final ImmutableSet<String> serviceAccountEmails;
|
||||
|
||||
protected OidcTokenAuthenticationMechanism(
|
||||
ImmutableSet<String> serviceAccountEmails,
|
||||
TokenVerifier tokenVerifier,
|
||||
@Nullable TokenVerifier fallbackTokenVerifier,
|
||||
TokenExtractor tokenExtractor) {
|
||||
TokenExtractor tokenExtractor,
|
||||
TokenVerifier tokenVerifier) {
|
||||
this.serviceAccountEmails = serviceAccountEmails;
|
||||
this.tokenVerifier = tokenVerifier;
|
||||
this.fallbackTokenVerifier = Optional.ofNullable(fallbackTokenVerifier);
|
||||
this.tokenExtractor = tokenExtractor;
|
||||
this.tokenVerifier = tokenVerifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,7 +83,12 @@ public abstract class OidcTokenAuthenticationMechanism implements Authentication
|
||||
}
|
||||
JsonWebSignature token = null;
|
||||
try {
|
||||
token = tokenVerifier.verify(rawIdToken);
|
||||
String service = null;
|
||||
if (RegistryEnvironment.isOnJetty()) {
|
||||
String hostname = request.getServerName();
|
||||
service = Splitter.on('.').split(hostname).iterator().next();
|
||||
}
|
||||
token = tokenVerifier.verify(service, rawIdToken);
|
||||
} catch (Exception e) {
|
||||
logger.atInfo().withCause(e).log(
|
||||
"Failed OIDC verification attempt:\n%s",
|
||||
@@ -97,20 +98,7 @@ public abstract class OidcTokenAuthenticationMechanism implements Authentication
|
||||
}
|
||||
|
||||
if (token == null) {
|
||||
if (fallbackTokenVerifier.isPresent()) {
|
||||
try {
|
||||
token = fallbackTokenVerifier.get().verify(rawIdToken);
|
||||
} catch (Exception e) {
|
||||
logger.atInfo().withCause(e).log(
|
||||
"Failed OIDC fallback verification attempt:\n%s",
|
||||
RegistryEnvironment.get().equals(RegistryEnvironment.PRODUCTION)
|
||||
? "Raw token redacted in prod"
|
||||
: rawIdToken);
|
||||
return AuthResult.NOT_AUTHENTICATED;
|
||||
}
|
||||
} else {
|
||||
return AuthResult.NOT_AUTHENTICATED;
|
||||
}
|
||||
return AuthResult.NOT_AUTHENTICATED;
|
||||
}
|
||||
|
||||
String email = (String) token.getPayload().get("email");
|
||||
@@ -155,6 +143,12 @@ public abstract class OidcTokenAuthenticationMechanism implements Authentication
|
||||
String extract(HttpServletRequest request);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
protected interface TokenVerifier {
|
||||
@Nullable
|
||||
JsonWebSignature verify(@Nullable String service, String rawToken) throws VerificationException;
|
||||
}
|
||||
|
||||
/**
|
||||
* A mechanism to authenticate HTTP requests that have gone through the GCP Identity-Aware Proxy.
|
||||
*
|
||||
@@ -171,9 +165,9 @@ public abstract class OidcTokenAuthenticationMechanism implements Authentication
|
||||
@Inject
|
||||
protected IapOidcAuthenticationMechanism(
|
||||
@Config("allowedServiceAccountEmails") ImmutableSet<String> serviceAccountEmails,
|
||||
@IapOidc TokenVerifier tokenVerifier,
|
||||
@IapOidc TokenExtractor tokenExtractor) {
|
||||
super(serviceAccountEmails, tokenVerifier, null, tokenExtractor);
|
||||
@IapOidc TokenExtractor tokenExtractor,
|
||||
@IapOidc TokenVerifier tokenVerifier) {
|
||||
super(serviceAccountEmails, tokenExtractor, tokenVerifier);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,10 +186,9 @@ public abstract class OidcTokenAuthenticationMechanism implements Authentication
|
||||
@Inject
|
||||
protected RegularOidcAuthenticationMechanism(
|
||||
@Config("allowedServiceAccountEmails") ImmutableSet<String> serviceAccountEmails,
|
||||
@RegularOidc TokenVerifier tokenVerifier,
|
||||
@RegularOidcFallback TokenVerifier fallbackTokenVerifier,
|
||||
@RegularOidc TokenExtractor tokenExtractor) {
|
||||
super(serviceAccountEmails, tokenVerifier, fallbackTokenVerifier, tokenExtractor);
|
||||
@RegularOidc TokenExtractor tokenExtractor,
|
||||
@RegularOidc TokenVerifier tokenVerifier) {
|
||||
super(serviceAccountEmails, tokenExtractor, tokenVerifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@ import google.registry.model.registrar.RegistrarPocBase;
|
||||
import google.registry.request.Action.Service;
|
||||
import google.registry.request.HttpException;
|
||||
import google.registry.security.XsrfTokenManager;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import google.registry.ui.server.registrar.ConsoleUiAction;
|
||||
import google.registry.util.DiffUtils;
|
||||
import google.registry.util.RegistryEnvironment;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.ui.server.registrar;
|
||||
package google.registry.ui.server.console;
|
||||
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
@@ -24,15 +24,16 @@ import google.registry.model.console.ConsolePermission;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Action.GkeService;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/** Returns a JSON representation of a domain to the registrar console. */
|
||||
@Action(
|
||||
service = Action.Service.DEFAULT,
|
||||
gkeService = GkeService.CONSOLE,
|
||||
path = ConsoleDomainGetAction.PATH,
|
||||
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
|
||||
public class ConsoleDomainGetAction extends ConsoleApiAction {
|
||||
|
||||
@@ -27,9 +27,9 @@ import google.registry.model.CreateAutoTimestamp;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Action.GkeService;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
@@ -39,6 +39,7 @@ import org.joda.time.DateTime;
|
||||
/** Returns a (paginated) list of domains for a particular registrar. */
|
||||
@Action(
|
||||
service = Action.Service.DEFAULT,
|
||||
gkeService = GkeService.CONSOLE,
|
||||
path = ConsoleDomainListAction.PATH,
|
||||
method = Action.Method.GET,
|
||||
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
|
||||
|
||||
@@ -26,9 +26,9 @@ import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.model.console.ConsolePermission;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Action.GkeService;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import google.registry.util.Clock;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
@@ -40,6 +40,7 @@ import org.joda.time.DateTime;
|
||||
|
||||
@Action(
|
||||
service = Action.Service.DEFAULT,
|
||||
gkeService = GkeService.CONSOLE,
|
||||
path = ConsoleDumDownloadAction.PATH,
|
||||
method = {GET},
|
||||
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
|
||||
|
||||
@@ -30,17 +30,18 @@ import google.registry.flows.PasswordOnlyTransportCredentials;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Action.GkeService;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
|
||||
import google.registry.request.auth.AuthenticatedRegistrarAccessor.RegistrarAccessDeniedException;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import google.registry.util.DiffUtils;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
|
||||
@Action(
|
||||
service = Action.Service.DEFAULT,
|
||||
gkeService = GkeService.CONSOLE,
|
||||
path = ConsoleEppPasswordAction.PATH,
|
||||
method = {POST},
|
||||
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.ui.server.registrar;
|
||||
package google.registry.ui.server.console;
|
||||
|
||||
import static google.registry.request.RequestParameters.extractBooleanParameter;
|
||||
import static google.registry.request.RequestParameters.extractOptionalIntParameter;
|
||||
@@ -34,6 +34,7 @@ import google.registry.request.auth.AuthResult;
|
||||
import google.registry.security.XsrfTokenManager;
|
||||
import google.registry.ui.server.SendEmailUtils;
|
||||
import google.registry.ui.server.console.ConsoleEppPasswordAction.EppPasswordData;
|
||||
import google.registry.ui.server.console.ConsoleOteAction.OteCreateData;
|
||||
import google.registry.ui.server.console.ConsoleRegistryLockAction.ConsoleRegistryLockPostInput;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.util.Optional;
|
||||
@@ -41,8 +42,8 @@ import org.joda.time.DateTime;
|
||||
|
||||
/** Dagger module for the Registrar Console parameters. */
|
||||
@Module
|
||||
public final class RegistrarConsoleModule {
|
||||
static final String PARAM_CLIENT_ID = "clientId";
|
||||
public final class ConsoleModule {
|
||||
public static final String PARAM_CLIENT_ID = "clientId";
|
||||
|
||||
@Provides
|
||||
@RequestScope
|
||||
@@ -244,6 +245,13 @@ public final class RegistrarConsoleModule {
|
||||
return payload.map(s -> gson.fromJson(s, EppPasswordData.class));
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Parameter("oteCreateData")
|
||||
public static Optional<OteCreateData> provideOteCreateData(
|
||||
Gson gson, @OptionalJsonPayload Optional<JsonElement> payload) {
|
||||
return payload.map(s -> gson.fromJson(s, OteCreateData.class));
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Parameter("consoleRegistryLockPostInput")
|
||||
public static Optional<ConsoleRegistryLockPostInput> provideRegistryLockPostInput(
|
||||
@@ -0,0 +1,174 @@
|
||||
// Copyright 2024 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.ui.server.console;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.request.Action.Method.GET;
|
||||
import static google.registry.request.Action.Method.POST;
|
||||
import static google.registry.util.RegistryEnvironment.PRODUCTION;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.model.OteAccountBuilder;
|
||||
import google.registry.model.OteStats;
|
||||
import google.registry.model.OteStats.StatType;
|
||||
import google.registry.model.console.ConsolePermission;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.RegistrarBase;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Action.GkeService;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.tools.IamClient;
|
||||
import google.registry.util.RegistryEnvironment;
|
||||
import google.registry.util.StringGenerator;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
@Action(
|
||||
service = Action.Service.DEFAULT,
|
||||
gkeService = GkeService.CONSOLE,
|
||||
path = ConsoleOteAction.PATH,
|
||||
method = {GET, POST},
|
||||
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
|
||||
public class ConsoleOteAction extends ConsoleApiAction {
|
||||
static final String PATH = "/console-api/ote";
|
||||
private static final int PASSWORD_LENGTH = 16;
|
||||
private static final String COMPLETED_PARAM = "completed";
|
||||
private static final String STAT_TYPE_DESCRIPTION_PARAM = "description";
|
||||
private static final String STAT_TYPE_REQUIREMENT_PARAM = "requirement";
|
||||
private static final String STAT_TYPE_TIMES_PERFORMED_PARAM = "timesPerformed";
|
||||
private final Gson gson;
|
||||
private final StringGenerator passwordGenerator;
|
||||
private final Optional<OteCreateData> oteCreateData;
|
||||
private final Optional<String> maybeGroupEmailAddress;
|
||||
private final IamClient iamClient;
|
||||
private final String registrarId;
|
||||
|
||||
@Inject
|
||||
public ConsoleOteAction(
|
||||
ConsoleApiParams consoleApiParams,
|
||||
Gson gson,
|
||||
IamClient iamClient,
|
||||
@Parameter("registrarId") String registrarId, // Get request param
|
||||
@Config("gSuiteConsoleUserGroupEmailAddress") Optional<String> maybeGroupEmailAddress,
|
||||
@Named("base58StringGenerator") StringGenerator passwordGenerator,
|
||||
@Parameter("oteCreateData") Optional<OteCreateData> oteCreateData) {
|
||||
super(consoleApiParams);
|
||||
this.gson = gson;
|
||||
this.passwordGenerator = passwordGenerator;
|
||||
this.oteCreateData = oteCreateData;
|
||||
this.maybeGroupEmailAddress = maybeGroupEmailAddress;
|
||||
this.iamClient = iamClient;
|
||||
this.registrarId = registrarId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postHandler(User user) {
|
||||
checkState(!RegistryEnvironment.get().equals(PRODUCTION), "Can't create OT&E in prod");
|
||||
|
||||
if (!user.getUserRoles().hasGlobalPermission(ConsolePermission.EDIT_REGISTRAR_DETAILS)) {
|
||||
setFailedResponse("User doesn't have a permission to create OT&E accounts", SC_FORBIDDEN);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isBodyValid =
|
||||
this.oteCreateData.isPresent()
|
||||
&& !this.oteCreateData.get().registrarId.isEmpty()
|
||||
&& !this.oteCreateData.get().registrarEmail.isEmpty();
|
||||
|
||||
checkArgument(isBodyValid, "OT&E create body is invalid");
|
||||
|
||||
String password = passwordGenerator.createString(PASSWORD_LENGTH);
|
||||
|
||||
OteAccountBuilder oteAccountBuilder =
|
||||
OteAccountBuilder.forRegistrarId(this.oteCreateData.get().registrarId)
|
||||
.addUser(this.oteCreateData.get().registrarEmail)
|
||||
.setPassword(password);
|
||||
|
||||
ImmutableMap<String, String> registrarIdToTld = oteAccountBuilder.buildAndPersist();
|
||||
oteAccountBuilder.grantIapPermission(maybeGroupEmailAddress, cloudTasksUtils, iamClient);
|
||||
consoleApiParams.response().setStatus(SC_OK);
|
||||
consoleApiParams
|
||||
.response()
|
||||
.setPayload(
|
||||
gson.toJson(
|
||||
ImmutableMap.builder().putAll(registrarIdToTld).put("password", password).build()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getHandler(User user) {
|
||||
checkArgument(!Strings.isNullOrEmpty(registrarId), "Missing registrarId parameter");
|
||||
|
||||
if (!user.getUserRoles().hasGlobalPermission(ConsolePermission.EDIT_REGISTRAR_DETAILS)) {
|
||||
setFailedResponse("User doesn't have a permission to check OT&E status", SC_BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
String baseRegistrarId = OteAccountBuilder.getBaseRegistrarId(registrarId);
|
||||
tm().transact(
|
||||
() -> {
|
||||
Optional<Registrar> registrar = Registrar.loadByRegistrarId(registrarId);
|
||||
if (registrar.isEmpty()) {
|
||||
setFailedResponse(
|
||||
String.format("Registrar with ID %s is not present", registrarId),
|
||||
SC_BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
if (!RegistrarBase.Type.OTE.equals(registrar.get().getType())) {
|
||||
setFailedResponse(
|
||||
String.format("Registrar with ID %s is not an OT&E registrar", registrarId),
|
||||
SC_BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
OteStats oteStats = OteStats.getFromRegistrar(baseRegistrarId);
|
||||
var stats =
|
||||
StatType.REQUIRED_STAT_TYPES.stream()
|
||||
.map(
|
||||
statType ->
|
||||
convertSingleRequirement(statType, oteStats.getCount(statType)))
|
||||
.collect(toImmutableList());
|
||||
consoleApiParams.response().setStatus(SC_OK);
|
||||
consoleApiParams.response().setPayload(gson.toJson(stats));
|
||||
});
|
||||
}
|
||||
|
||||
private Map<String, Object> convertSingleRequirement(StatType statType, int count) {
|
||||
int requirement = statType.getRequirement();
|
||||
return ImmutableMap.of(
|
||||
STAT_TYPE_DESCRIPTION_PARAM,
|
||||
statType.getDescription(),
|
||||
STAT_TYPE_REQUIREMENT_PARAM,
|
||||
requirement,
|
||||
STAT_TYPE_TIMES_PERFORMED_PARAM,
|
||||
count,
|
||||
COMPLETED_PARAM,
|
||||
count >= requirement);
|
||||
}
|
||||
|
||||
public record OteCreateData(@Expose String registrarId, @Expose String registrarEmail) {}
|
||||
}
|
||||
@@ -35,11 +35,11 @@ import google.registry.model.domain.RegistryLock;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.tld.RegistryLockDao;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Action.GkeService;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.tools.DomainLockUtils;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import google.registry.util.EmailMessage;
|
||||
import jakarta.mail.internet.AddressException;
|
||||
import jakarta.mail.internet.InternetAddress;
|
||||
@@ -56,6 +56,7 @@ import org.joda.time.Duration;
|
||||
*/
|
||||
@Action(
|
||||
service = Action.Service.DEFAULT,
|
||||
gkeService = GkeService.CONSOLE,
|
||||
path = ConsoleRegistryLockAction.PATH,
|
||||
method = {GET, POST},
|
||||
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
|
||||
|
||||
@@ -22,16 +22,17 @@ import com.google.gson.annotations.Expose;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.domain.RegistryLock;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Action.GkeService;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.tools.DomainLockUtils;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/** Handler for verifying registry lock requests, a form of 2FA. */
|
||||
@Action(
|
||||
service = Action.Service.DEFAULT,
|
||||
gkeService = GkeService.CONSOLE,
|
||||
path = ConsoleRegistryLockVerifyAction.PATH,
|
||||
method = {GET},
|
||||
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
|
||||
|
||||
@@ -26,10 +26,10 @@ import google.registry.model.console.ConsolePermission;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Action.GkeService;
|
||||
import google.registry.request.HttpException.BadRequestException;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import google.registry.util.DomainNameUtils;
|
||||
import google.registry.util.RegistryEnvironment;
|
||||
import java.util.Optional;
|
||||
@@ -38,6 +38,7 @@ import javax.inject.Inject;
|
||||
|
||||
@Action(
|
||||
service = Action.Service.DEFAULT,
|
||||
gkeService = GkeService.CONSOLE,
|
||||
path = ConsoleUpdateRegistrarAction.PATH,
|
||||
method = {POST},
|
||||
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
|
||||
|
||||
@@ -21,15 +21,16 @@ import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Action.GkeService;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.security.XsrfTokenManager;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import jakarta.servlet.http.Cookie;
|
||||
import javax.inject.Inject;
|
||||
import org.json.JSONObject;
|
||||
|
||||
@Action(
|
||||
service = Action.Service.DEFAULT,
|
||||
gkeService = GkeService.CONSOLE,
|
||||
path = ConsoleUserDataAction.PATH,
|
||||
method = {GET},
|
||||
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
|
||||
|
||||
@@ -34,9 +34,9 @@ import google.registry.model.registrar.RegistrarBase;
|
||||
import google.registry.model.registrar.RegistrarBase.State;
|
||||
import google.registry.model.registrar.RegistrarPoc;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Action.GkeService;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import google.registry.util.StringGenerator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -46,6 +46,7 @@ import javax.inject.Named;
|
||||
|
||||
@Action(
|
||||
service = Action.Service.DEFAULT,
|
||||
gkeService = GkeService.CONSOLE,
|
||||
path = RegistrarsAction.PATH,
|
||||
method = {GET, POST},
|
||||
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
|
||||
|
||||
@@ -31,11 +31,12 @@ import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.RegistrarPoc;
|
||||
import google.registry.persistence.transaction.QueryComposer.Comparator;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Action.GkeService;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.ui.forms.FormException;
|
||||
import google.registry.ui.server.console.ConsoleApiAction;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import google.registry.ui.server.console.ConsoleApiParams;
|
||||
import google.registry.ui.server.registrar.RegistrarSettingsAction;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
@@ -43,6 +44,7 @@ import javax.inject.Inject;
|
||||
|
||||
@Action(
|
||||
service = Action.Service.DEFAULT,
|
||||
gkeService = GkeService.CONSOLE,
|
||||
path = ContactAction.PATH,
|
||||
method = {GET, POST},
|
||||
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
|
||||
|
||||
@@ -28,17 +28,19 @@ import google.registry.model.console.ConsolePermission;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Action.GkeService;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
|
||||
import google.registry.request.auth.AuthenticatedRegistrarAccessor.RegistrarAccessDeniedException;
|
||||
import google.registry.ui.server.console.ConsoleApiAction;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import google.registry.ui.server.console.ConsoleApiParams;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
|
||||
@Action(
|
||||
service = Action.Service.DEFAULT,
|
||||
gkeService = GkeService.CONSOLE,
|
||||
path = SecurityAction.PATH,
|
||||
method = {POST},
|
||||
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
|
||||
|
||||
@@ -25,12 +25,13 @@ import google.registry.model.console.ConsolePermission;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Action.GkeService;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
|
||||
import google.registry.request.auth.AuthenticatedRegistrarAccessor.RegistrarAccessDeniedException;
|
||||
import google.registry.ui.server.console.ConsoleApiAction;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import google.registry.ui.server.console.ConsoleApiParams;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
@@ -43,6 +44,7 @@ import javax.inject.Inject;
|
||||
*/
|
||||
@Action(
|
||||
service = Action.Service.DEFAULT,
|
||||
gkeService = GkeService.CONSOLE,
|
||||
path = WhoisRegistrarFieldsAction.PATH,
|
||||
method = {POST},
|
||||
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
|
||||
|
||||
@@ -18,7 +18,7 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.security.JsonResponseHelper.Status.SUCCESS;
|
||||
import static google.registry.ui.server.registrar.RegistrarConsoleModule.PARAM_CLIENT_ID;
|
||||
import static google.registry.ui.server.console.ConsoleModule.PARAM_CLIENT_ID;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import google.registry.module.backend.BackendRequestComponent;
|
||||
import google.registry.module.bsa.BsaRequestComponent;
|
||||
import google.registry.module.frontend.FrontendRequestComponent;
|
||||
@@ -26,8 +28,9 @@ import google.registry.module.pubapi.PubApiRequestComponent;
|
||||
import google.registry.module.tools.ToolsRequestComponent;
|
||||
import google.registry.testing.GoldenFileTestHelper;
|
||||
import google.registry.testing.TestDataHelper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link RequestComponent}. */
|
||||
@@ -40,6 +43,18 @@ public class RequestComponentTest {
|
||||
PubApiRequestComponent.class, "pubapi",
|
||||
BsaRequestComponent.class, "bsa");
|
||||
|
||||
// Paths that do not route to Jetty (all for the legacy console).
|
||||
private static final ImmutableSet<String> ignoredPaths =
|
||||
ImmutableSet.of(
|
||||
"/registrar",
|
||||
"/registrar-create",
|
||||
"/registrar-ote-setup",
|
||||
"/registrar-ote-status",
|
||||
"/registrar-settings",
|
||||
"/registry-lock-get",
|
||||
"/registry-lock-post",
|
||||
"/registry-lock-verify");
|
||||
|
||||
@Test
|
||||
void testRoutingMap() {
|
||||
GoldenFileTestHelper.assertThatRoutesFromComponent(RequestComponent.class)
|
||||
@@ -49,32 +64,49 @@ public class RequestComponentTest {
|
||||
|
||||
@Test
|
||||
void testGaeToJettyRoutingCoverage() {
|
||||
List<Route> jettyRoutes = getRoutes(RequestComponent.class, "routing.txt");
|
||||
List<Route> gaeRoutes = new ArrayList<>();
|
||||
Set<Route> jettyRoutes = getRoutes(RequestComponent.class, "routing.txt");
|
||||
Set<Route> gaeRoutes = new HashSet<>();
|
||||
for (var component : GaeComponents.entrySet()) {
|
||||
gaeRoutes.addAll(getRoutes(component.getKey(), component.getValue() + "_routing.txt"));
|
||||
}
|
||||
assertThat(jettyRoutes).containsExactlyElementsIn(gaeRoutes);
|
||||
assertThat(Sets.difference(jettyRoutes, gaeRoutes)).isEmpty();
|
||||
assertThat(
|
||||
Sets.difference(gaeRoutes, jettyRoutes).stream()
|
||||
.map(Route::path)
|
||||
.collect(Collectors.toSet()))
|
||||
.containsExactlyElementsIn(ignoredPaths);
|
||||
}
|
||||
|
||||
private List<Route> getRoutes(Class<?> context, String filename) {
|
||||
private Set<Route> getRoutes(Class<?> context, String filename) {
|
||||
return TestDataHelper.loadFile(context, filename)
|
||||
.trim()
|
||||
.lines()
|
||||
.skip(1) // Skip the headers
|
||||
.map(Route::create)
|
||||
.toList();
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private record Route(
|
||||
String path, String clazz, String methods, String ok, String min, String userPolicy) {
|
||||
String service,
|
||||
String path,
|
||||
String clazz,
|
||||
String methods,
|
||||
String ok,
|
||||
String min,
|
||||
String userPolicy) {
|
||||
private static final Splitter splitter = Splitter.on(' ').omitEmptyStrings().trimResults();
|
||||
|
||||
static Route create(String line) {
|
||||
ImmutableList<String> parts = ImmutableList.copyOf(splitter.split(line));
|
||||
assertThat(parts.size()).isEqualTo(6);
|
||||
assertThat(parts.size()).isEqualTo(7);
|
||||
return new Route(
|
||||
parts.get(0), parts.get(1), parts.get(2), parts.get(3), parts.get(4), parts.get(5));
|
||||
parts.get(0),
|
||||
parts.get(1),
|
||||
parts.get(2),
|
||||
parts.get(3),
|
||||
parts.get(4),
|
||||
parts.get(5),
|
||||
parts.get(6));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,6 +204,7 @@ public final class RequestHandlerTest {
|
||||
handler =
|
||||
RequestHandler.create(
|
||||
Component.class,
|
||||
"registry.test",
|
||||
() ->
|
||||
new Builder() {
|
||||
@Override
|
||||
|
||||
@@ -26,8 +26,8 @@ import static org.mockito.Mockito.when;
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
|
||||
import com.google.api.client.json.webtoken.JsonWebSignature;
|
||||
import com.google.api.client.json.webtoken.JsonWebSignature.Header;
|
||||
import com.google.auth.oauth2.TokenVerifier;
|
||||
import com.google.auth.oauth2.TokenVerifier.VerificationException;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import dagger.Component;
|
||||
import dagger.Module;
|
||||
@@ -41,6 +41,7 @@ import google.registry.request.auth.AuthSettings.AuthLevel;
|
||||
import google.registry.request.auth.OidcTokenAuthenticationMechanism.IapOidcAuthenticationMechanism;
|
||||
import google.registry.request.auth.OidcTokenAuthenticationMechanism.RegularOidcAuthenticationMechanism;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.util.Map;
|
||||
import javax.inject.Singleton;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -59,13 +60,13 @@ public class OidcTokenAuthenticationMechanismTest {
|
||||
private final Payload payload = new Payload();
|
||||
private final JsonWebSignature jwt =
|
||||
new JsonWebSignature(new Header(), payload, new byte[0], new byte[0]);
|
||||
private final TokenVerifier tokenVerifier = mock(TokenVerifier.class);
|
||||
private final HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
|
||||
private User user;
|
||||
private AuthResult authResult;
|
||||
private OidcTokenAuthenticationMechanism authenticationMechanism =
|
||||
new OidcTokenAuthenticationMechanism(serviceAccounts, tokenVerifier, null, e -> rawToken) {};
|
||||
new OidcTokenAuthenticationMechanism(
|
||||
serviceAccounts, request -> rawToken, (service, token) -> jwt) {};
|
||||
|
||||
@RegisterExtension
|
||||
public final JpaTestExtensions.JpaUnitTestExtension jpaExtension =
|
||||
@@ -73,7 +74,6 @@ public class OidcTokenAuthenticationMechanismTest {
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() throws Exception {
|
||||
when(tokenVerifier.verify(rawToken)).thenReturn(jwt);
|
||||
payload.setEmail(email);
|
||||
payload.setSubject(gaiaId);
|
||||
user = createAdminUser(email);
|
||||
@@ -93,28 +93,23 @@ public class OidcTokenAuthenticationMechanismTest {
|
||||
@Test
|
||||
void testAuthenticate_noTokenFromRequest() {
|
||||
authenticationMechanism =
|
||||
new OidcTokenAuthenticationMechanism(serviceAccounts, tokenVerifier, null, e -> null) {};
|
||||
new OidcTokenAuthenticationMechanism(
|
||||
serviceAccounts, e -> null, (service, token) -> jwt) {};
|
||||
authResult = authenticationMechanism.authenticate(request);
|
||||
assertThat(authResult).isEqualTo(AuthResult.NOT_AUTHENTICATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAuthenticate_invalidToken() throws Exception {
|
||||
when(tokenVerifier.verify(rawToken)).thenThrow(new VerificationException("Bad token"));
|
||||
authResult = authenticationMechanism.authenticate(request);
|
||||
assertThat(authResult).isEqualTo(AuthResult.NOT_AUTHENTICATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAuthenticate_fallbackVerifier() throws Exception {
|
||||
TokenVerifier fallbackVerifier = mock(TokenVerifier.class);
|
||||
when(tokenVerifier.verify(rawToken)).thenThrow(new VerificationException("Bad token"));
|
||||
when(fallbackVerifier.verify(rawToken)).thenReturn(jwt);
|
||||
authenticationMechanism =
|
||||
new OidcTokenAuthenticationMechanism(
|
||||
serviceAccounts, tokenVerifier, fallbackVerifier, e -> rawToken) {};
|
||||
serviceAccounts,
|
||||
e -> null,
|
||||
(service, token) -> {
|
||||
throw new VerificationException("Bad token");
|
||||
}) {};
|
||||
authResult = authenticationMechanism.authenticate(request);
|
||||
assertThat(authResult.isAuthenticated()).isEqualTo(true);
|
||||
assertThat(authResult).isEqualTo(AuthResult.NOT_AUTHENTICATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -233,9 +228,9 @@ public class OidcTokenAuthenticationMechanismTest {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Config("fallbackOauthClientId")
|
||||
String provideFallbackOauthClientId() {
|
||||
return "fallback-client-id";
|
||||
@Config("backendServiceIds")
|
||||
Map<String, Long> provideBackendServiceIds() {
|
||||
return ImmutableMap.of();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import google.registry.model.console.User;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.security.XsrfTokenManager;
|
||||
import google.registry.ui.server.SendEmailUtils;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import google.registry.ui.server.console.ConsoleApiParams;
|
||||
import jakarta.servlet.http.Cookie;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
@@ -33,7 +33,6 @@ import google.registry.request.auth.AuthResult;
|
||||
import google.registry.testing.ConsoleApiParamsUtils;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
@@ -36,7 +36,6 @@ import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.tools.GsonUtils;
|
||||
import google.registry.ui.server.console.ConsoleDomainListAction.DomainListResult;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
@@ -33,7 +33,6 @@ import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.tools.GsonUtils;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import java.io.IOException;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
||||
@@ -44,8 +44,6 @@ import google.registry.testing.ConsoleApiParamsUtils;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.tools.GsonUtils;
|
||||
import google.registry.ui.server.console.ConsoleEppPasswordAction.EppPasswordData;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import google.registry.ui.server.registrar.RegistrarConsoleModule;
|
||||
import google.registry.util.EmailMessage;
|
||||
import jakarta.mail.internet.AddressException;
|
||||
import jakarta.mail.internet.InternetAddress;
|
||||
@@ -167,7 +165,7 @@ class ConsoleEppPasswordActionTest {
|
||||
.when(consoleApiParams.request())
|
||||
.getReader();
|
||||
Optional<EppPasswordData> maybePasswordChangeRequest =
|
||||
RegistrarConsoleModule.provideEppPasswordChangeRequest(
|
||||
ConsoleModule.provideEppPasswordChangeRequest(
|
||||
GSON, RequestModule.provideJsonBody(consoleApiParams.request(), GSON));
|
||||
|
||||
return new ConsoleEppPasswordAction(
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
// Copyright 2024 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.ui.server.console;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.OteAccountBuilderTest.verifyIapPermission;
|
||||
import static google.registry.testing.DatabaseHelper.persistPremiumList;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.model.OteStatsTestHelper;
|
||||
import google.registry.model.console.GlobalRole;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserRoles;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
import google.registry.testing.ConsoleApiParamsUtils;
|
||||
import google.registry.testing.DeterministicStringGenerator;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.tools.GsonUtils;
|
||||
import google.registry.tools.IamClient;
|
||||
import google.registry.ui.server.console.ConsoleOteAction.OteCreateData;
|
||||
import google.registry.util.StringGenerator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
class ConsoleOteActionTest {
|
||||
|
||||
@RegisterExtension
|
||||
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
|
||||
private static final Gson GSON = GsonUtils.provideGson();
|
||||
private final IamClient iamClient = mock(IamClient.class);
|
||||
private final CloudTasksHelper cloudTasksHelper = new CloudTasksHelper();
|
||||
private FakeResponse response;
|
||||
private ConsoleApiParams consoleApiParams;
|
||||
|
||||
private StringGenerator passwordGenerator =
|
||||
new DeterministicStringGenerator("abcdefghijklmnopqrstuvwxyz");
|
||||
|
||||
private User user =
|
||||
new User.Builder()
|
||||
.setEmailAddress("marla.singer@example.com")
|
||||
.setUserRoles(new UserRoles())
|
||||
.build();
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() throws Exception {
|
||||
persistPremiumList("default_sandbox_list", USD, "sandbox,USD 1000");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_missingGlobalPermission() {
|
||||
AuthResult authResult = AuthResult.createUser(user);
|
||||
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
|
||||
ConsoleOteAction action =
|
||||
createAction(
|
||||
Action.Method.POST,
|
||||
authResult,
|
||||
"testRegistrarId",
|
||||
Optional.of("someRandomString"),
|
||||
Optional.of(new OteCreateData("testRegistrarId", "tescontact@registry.example")));
|
||||
action.run();
|
||||
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_FORBIDDEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_invalidParamsNoRegistrarId() {
|
||||
user =
|
||||
user.asBuilder()
|
||||
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
|
||||
.build();
|
||||
AuthResult authResult = AuthResult.createUser(user);
|
||||
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
|
||||
ConsoleOteAction action =
|
||||
createAction(
|
||||
Action.Method.POST,
|
||||
authResult,
|
||||
"testRegistrarId",
|
||||
Optional.of("someRandomString"),
|
||||
Optional.of(new OteCreateData("", "test@email.com")));
|
||||
action.run();
|
||||
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
|
||||
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
|
||||
.isEqualTo("OT&E create body is invalid");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_invalidParamsNoEmail() {
|
||||
user =
|
||||
user.asBuilder()
|
||||
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
|
||||
.build();
|
||||
AuthResult authResult = AuthResult.createUser(user);
|
||||
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
|
||||
ConsoleOteAction action =
|
||||
createAction(
|
||||
Action.Method.POST,
|
||||
authResult,
|
||||
"testRegistrarId",
|
||||
Optional.of("someRandomString"),
|
||||
Optional.of(new OteCreateData("testRegistrarId", "")));
|
||||
action.run();
|
||||
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
|
||||
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
|
||||
.isEqualTo("OT&E create body is invalid");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_oteCreated() {
|
||||
user =
|
||||
user.asBuilder()
|
||||
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
|
||||
.build();
|
||||
AuthResult authResult = AuthResult.createUser(user);
|
||||
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
|
||||
ConsoleOteAction action =
|
||||
createAction(
|
||||
Action.Method.POST,
|
||||
authResult,
|
||||
"theregistrar",
|
||||
Optional.of("someRandomString@email.test"),
|
||||
Optional.of(new OteCreateData("theregistrar", "contact@registry.example")));
|
||||
action.cloudTasksUtils = cloudTasksHelper.getTestCloudTasksUtils();
|
||||
action.run();
|
||||
String response = ((FakeResponse) consoleApiParams.response()).getPayload();
|
||||
var obsResponse = GSON.fromJson(response, Map.class);
|
||||
assertThat(
|
||||
ImmutableMap.of(
|
||||
"theregistrar-1", "theregistrar-sunrise",
|
||||
"theregistrar-3", "theregistrar-ga",
|
||||
"theregistrar-4", "theregistrar-ga",
|
||||
"theregistrar-5", "theregistrar-eap",
|
||||
"password", "abcdefghijklmnop"))
|
||||
.containsExactlyEntriesIn(obsResponse);
|
||||
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
|
||||
verifyIapPermission(
|
||||
"contact@registry.example",
|
||||
Optional.of("someRandomString@email.test"),
|
||||
cloudTasksHelper,
|
||||
iamClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFail_statusMissingParam() {
|
||||
AuthResult authResult = AuthResult.createUser(user);
|
||||
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
|
||||
ConsoleOteAction action =
|
||||
createAction(
|
||||
Action.Method.GET,
|
||||
authResult,
|
||||
"",
|
||||
Optional.of("someRandomString@email.test"),
|
||||
Optional.of(new OteCreateData("theregistrar", "contact@registry.example")));
|
||||
action.cloudTasksUtils = cloudTasksHelper.getTestCloudTasksUtils();
|
||||
action.run();
|
||||
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_BAD_REQUEST);
|
||||
assertThat(((FakeResponse) consoleApiParams.response()).getPayload())
|
||||
.isEqualTo("Missing registrarId parameter");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_finishedOte() throws Exception {
|
||||
OteStatsTestHelper.setupCompleteOte("theregistrar");
|
||||
user =
|
||||
user.asBuilder()
|
||||
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
|
||||
.build();
|
||||
AuthResult authResult = AuthResult.createUser(user);
|
||||
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
|
||||
ConsoleOteAction action =
|
||||
createAction(
|
||||
Action.Method.GET, authResult, "theregistrar-1", Optional.empty(), Optional.empty());
|
||||
action.run();
|
||||
|
||||
List<Map<String, ?>> response =
|
||||
GSON.fromJson(((FakeResponse) consoleApiParams.response()).getPayload(), JSONArray.class);
|
||||
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
|
||||
assertTrue(response.stream().allMatch(status -> Boolean.TRUE.equals(status.get("completed"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_unfinishedOte() throws Exception {
|
||||
OteStatsTestHelper.setupIncompleteOte("theregistrar");
|
||||
user =
|
||||
user.asBuilder()
|
||||
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
|
||||
.build();
|
||||
AuthResult authResult = AuthResult.createUser(user);
|
||||
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
|
||||
ConsoleOteAction action =
|
||||
createAction(
|
||||
Action.Method.GET, authResult, "theregistrar-1", Optional.empty(), Optional.empty());
|
||||
action.run();
|
||||
|
||||
List<Map<String, ?>> response =
|
||||
GSON.fromJson(((FakeResponse) consoleApiParams.response()).getPayload(), JSONArray.class);
|
||||
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
|
||||
assertThat(
|
||||
response.stream()
|
||||
.filter(status -> Boolean.FALSE.equals(status.get("completed")))
|
||||
.map(status -> status.get("description"))
|
||||
.collect(Collectors.toList()))
|
||||
.containsExactlyElementsIn(
|
||||
ImmutableList.of("domain creates idn", "domain restores", "host deletes"));
|
||||
}
|
||||
|
||||
private ConsoleOteAction createAction(
|
||||
Action.Method method,
|
||||
AuthResult authResult,
|
||||
String registrarId,
|
||||
Optional<String> maybeGroupEmailAddress,
|
||||
Optional<OteCreateData> oteCreateData) {
|
||||
response = new FakeResponse();
|
||||
consoleApiParams = ConsoleApiParamsUtils.createFake(authResult);
|
||||
when(consoleApiParams.request().getMethod()).thenReturn(method.toString());
|
||||
return new ConsoleOteAction(
|
||||
consoleApiParams,
|
||||
GSON,
|
||||
iamClient,
|
||||
registrarId,
|
||||
maybeGroupEmailAddress,
|
||||
passwordGenerator,
|
||||
oteCreateData);
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,6 @@ import google.registry.testing.DeterministicStringGenerator;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.tools.DomainLockUtils;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import google.registry.util.EmailMessage;
|
||||
import google.registry.util.StringGenerator;
|
||||
import jakarta.mail.internet.InternetAddress;
|
||||
|
||||
@@ -40,7 +40,6 @@ import google.registry.testing.DeterministicStringGenerator;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.tools.DomainLockUtils;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import google.registry.util.StringGenerator;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
@@ -42,8 +42,6 @@ import google.registry.testing.ConsoleApiParamsUtils;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.testing.SystemPropertyExtension;
|
||||
import google.registry.tools.GsonUtils;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import google.registry.ui.server.registrar.RegistrarConsoleModule;
|
||||
import google.registry.util.EmailMessage;
|
||||
import google.registry.util.RegistryEnvironment;
|
||||
import jakarta.mail.internet.AddressException;
|
||||
@@ -172,7 +170,7 @@ class ConsoleUpdateRegistrarActionTest {
|
||||
.when(consoleApiParams.request())
|
||||
.getReader();
|
||||
Optional<Registrar> maybeRegistrarUpdateData =
|
||||
RegistrarConsoleModule.provideRegistrar(
|
||||
ConsoleModule.provideRegistrar(
|
||||
GSON, RequestModule.provideJsonBody(consoleApiParams.request(), GSON));
|
||||
return new ConsoleUpdateRegistrarAction(consoleApiParams, maybeRegistrarUpdateData);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import google.registry.request.auth.AuthResult;
|
||||
import google.registry.testing.ConsoleApiParamsUtils;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import jakarta.servlet.http.Cookie;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
@@ -41,8 +41,6 @@ import google.registry.request.auth.AuthResult;
|
||||
import google.registry.testing.ConsoleApiParamsUtils;
|
||||
import google.registry.testing.DeterministicStringGenerator;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import google.registry.ui.server.registrar.RegistrarConsoleModule;
|
||||
import google.registry.util.StringGenerator;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
@@ -253,7 +251,7 @@ class RegistrarsActionTest {
|
||||
passcodeGenerator);
|
||||
}
|
||||
Optional<Registrar> maybeRegistrar =
|
||||
RegistrarConsoleModule.provideRegistrar(
|
||||
ConsoleModule.provideRegistrar(
|
||||
GSON, RequestModule.provideJsonBody(consoleApiParams.request(), GSON));
|
||||
return new RegistrarsAction(
|
||||
consoleApiParams, GSON, maybeRegistrar, passwordGenerator, passcodeGenerator);
|
||||
|
||||
@@ -45,8 +45,8 @@ import google.registry.request.RequestModule;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.testing.ConsoleApiParamsUtils;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import google.registry.ui.server.registrar.RegistrarConsoleModule;
|
||||
import google.registry.ui.server.console.ConsoleApiParams;
|
||||
import google.registry.ui.server.console.ConsoleModule;
|
||||
import google.registry.util.EmailMessage;
|
||||
import jakarta.mail.internet.AddressException;
|
||||
import jakarta.mail.internet.InternetAddress;
|
||||
@@ -296,7 +296,7 @@ class ContactActionTest {
|
||||
.when(consoleApiParams.request())
|
||||
.getReader();
|
||||
Optional<ImmutableSet<RegistrarPoc>> maybeContacts =
|
||||
RegistrarConsoleModule.provideContacts(
|
||||
ConsoleModule.provideContacts(
|
||||
GSON, RequestModule.provideJsonBody(consoleApiParams.request(), GSON));
|
||||
return new ContactAction(consoleApiParams, GSON, registrarId, maybeContacts);
|
||||
}
|
||||
|
||||
@@ -38,8 +38,8 @@ import google.registry.testing.ConsoleApiParamsUtils;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import google.registry.ui.server.registrar.RegistrarConsoleModule;
|
||||
import google.registry.ui.server.console.ConsoleApiParams;
|
||||
import google.registry.ui.server.console.ConsoleModule;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
@@ -108,7 +108,7 @@ class SecurityActionTest {
|
||||
.when(consoleApiParams.request())
|
||||
.getReader();
|
||||
Optional<Registrar> maybeRegistrar =
|
||||
RegistrarConsoleModule.provideRegistrar(
|
||||
ConsoleModule.provideRegistrar(
|
||||
GSON, RequestModule.provideJsonBody(consoleApiParams.request(), GSON));
|
||||
return new SecurityAction(
|
||||
consoleApiParams, certificateChecker, registrarAccessor, registrarId, maybeRegistrar);
|
||||
|
||||
@@ -40,8 +40,8 @@ import google.registry.testing.ConsoleApiParamsUtils;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.ui.server.registrar.ConsoleApiParams;
|
||||
import google.registry.ui.server.registrar.RegistrarConsoleModule;
|
||||
import google.registry.ui.server.console.ConsoleApiParams;
|
||||
import google.registry.ui.server.console.ConsoleModule;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
@@ -169,7 +169,7 @@ public class WhoisRegistrarFieldsActionTest {
|
||||
return new WhoisRegistrarFieldsAction(
|
||||
consoleApiParams,
|
||||
registrarAccessor,
|
||||
RegistrarConsoleModule.provideRegistrar(
|
||||
ConsoleModule.provideRegistrar(
|
||||
GSON, RequestModule.provideJsonBody(consoleApiParams.request(), GSON)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
PATH CLASS METHODS OK MIN USER_POLICY
|
||||
/_dr/cron/fanout TldFanoutAction GET y APP ADMIN
|
||||
/_dr/dnsRefresh RefreshDnsAction GET y APP ADMIN
|
||||
/_dr/task/brdaCopy BrdaCopyAction POST y APP ADMIN
|
||||
/_dr/task/copyDetailReports CopyDetailReportsAction POST n APP ADMIN
|
||||
/_dr/task/deleteExpiredDomains DeleteExpiredDomainsAction GET n APP ADMIN
|
||||
/_dr/task/deleteLoadTestData DeleteLoadTestDataAction POST n APP ADMIN
|
||||
/_dr/task/deleteProberData DeleteProberDataAction POST n APP ADMIN
|
||||
/_dr/task/executeCannedScript CannedScriptExecutionAction POST,GET y APP ADMIN
|
||||
/_dr/task/expandBillingRecurrences ExpandBillingRecurrencesAction GET n APP ADMIN
|
||||
/_dr/task/exportDomainLists ExportDomainListsAction POST n APP ADMIN
|
||||
/_dr/task/exportPremiumTerms ExportPremiumTermsAction POST n APP ADMIN
|
||||
/_dr/task/exportReservedTerms ExportReservedTermsAction POST n APP ADMIN
|
||||
/_dr/task/generateInvoices GenerateInvoicesAction POST n APP ADMIN
|
||||
/_dr/task/generateSpec11 GenerateSpec11ReportAction POST n APP ADMIN
|
||||
/_dr/task/icannReportingStaging IcannReportingStagingAction POST n APP ADMIN
|
||||
/_dr/task/icannReportingUpload IcannReportingUploadAction POST n APP ADMIN
|
||||
/_dr/task/nordnUpload NordnUploadAction POST y APP ADMIN
|
||||
/_dr/task/nordnVerify NordnVerifyAction POST y APP ADMIN
|
||||
/_dr/task/publishDnsUpdates PublishDnsUpdatesAction POST y APP ADMIN
|
||||
/_dr/task/publishInvoices PublishInvoicesAction POST n APP ADMIN
|
||||
/_dr/task/publishSpec11 PublishSpec11ReportAction POST n APP ADMIN
|
||||
/_dr/task/rdeReport RdeReportAction POST n APP ADMIN
|
||||
/_dr/task/rdeStaging RdeStagingAction GET,POST n APP ADMIN
|
||||
/_dr/task/rdeUpload RdeUploadAction POST n APP ADMIN
|
||||
/_dr/task/readDnsRefreshRequests ReadDnsRefreshRequestsAction POST y APP ADMIN
|
||||
/_dr/task/refreshDnsOnHostRename RefreshDnsOnHostRenameAction POST n APP ADMIN
|
||||
/_dr/task/relockDomain RelockDomainAction POST y APP ADMIN
|
||||
/_dr/task/resaveAllEppResourcesPipeline ResaveAllEppResourcesPipelineAction GET n APP ADMIN
|
||||
/_dr/task/resaveEntity ResaveEntityAction POST n APP ADMIN
|
||||
/_dr/task/sendExpiringCertificateNotificationEmail SendExpiringCertificateNotificationEmailAction GET n APP ADMIN
|
||||
/_dr/task/syncGroupMembers SyncGroupMembersAction POST n APP ADMIN
|
||||
/_dr/task/syncRegistrarsSheet SyncRegistrarsSheetAction POST n APP ADMIN
|
||||
/_dr/task/tmchCrl TmchCrlAction POST y APP ADMIN
|
||||
/_dr/task/tmchDnl TmchDnlAction POST y APP ADMIN
|
||||
/_dr/task/tmchSmdrl TmchSmdrlAction POST y APP ADMIN
|
||||
/_dr/task/updateRegistrarRdapBaseUrls UpdateRegistrarRdapBaseUrlsAction GET y APP ADMIN
|
||||
/_dr/task/wipeOutContactHistoryPii WipeOutContactHistoryPiiAction GET n APP ADMIN
|
||||
SERVICE PATH CLASS METHODS OK MIN USER_POLICY
|
||||
BACKEND /_dr/cron/fanout TldFanoutAction GET y APP ADMIN
|
||||
BACKEND /_dr/task/brdaCopy BrdaCopyAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/copyDetailReports CopyDetailReportsAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/deleteExpiredDomains DeleteExpiredDomainsAction GET n APP ADMIN
|
||||
BACKEND /_dr/task/deleteLoadTestData DeleteLoadTestDataAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/deleteProberData DeleteProberDataAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/dnsRefresh RefreshDnsAction GET y APP ADMIN
|
||||
BACKEND /_dr/task/executeCannedScript CannedScriptExecutionAction POST,GET y APP ADMIN
|
||||
BACKEND /_dr/task/expandBillingRecurrences ExpandBillingRecurrencesAction GET n APP ADMIN
|
||||
BACKEND /_dr/task/exportDomainLists ExportDomainListsAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/exportPremiumTerms ExportPremiumTermsAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/exportReservedTerms ExportReservedTermsAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/generateInvoices GenerateInvoicesAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/generateSpec11 GenerateSpec11ReportAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/icannReportingStaging IcannReportingStagingAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/icannReportingUpload IcannReportingUploadAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/nordnUpload NordnUploadAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/nordnVerify NordnVerifyAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/publishDnsUpdates PublishDnsUpdatesAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/publishInvoices PublishInvoicesAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/publishSpec11 PublishSpec11ReportAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/rdeReport RdeReportAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/rdeStaging RdeStagingAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/task/rdeUpload RdeUploadAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/readDnsRefreshRequests ReadDnsRefreshRequestsAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/refreshDnsOnHostRename RefreshDnsOnHostRenameAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/relockDomain RelockDomainAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/resaveAllEppResourcesPipeline ResaveAllEppResourcesPipelineAction GET n APP ADMIN
|
||||
BACKEND /_dr/task/resaveEntity ResaveEntityAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/sendExpiringCertificateNotificationEmail SendExpiringCertificateNotificationEmailAction GET n APP ADMIN
|
||||
BACKEND /_dr/task/syncGroupMembers SyncGroupMembersAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/syncRegistrarsSheet SyncRegistrarsSheetAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/tmchCrl TmchCrlAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/tmchDnl TmchDnlAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/tmchSmdrl TmchSmdrlAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/updateRegistrarRdapBaseUrls UpdateRegistrarRdapBaseUrlsAction GET y APP ADMIN
|
||||
BACKEND /_dr/task/wipeOutContactHistoryPii WipeOutContactHistoryPiiAction GET n APP ADMIN
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
PATH CLASS METHODS OK MIN USER_POLICY
|
||||
/_dr/task/bsaDownload BsaDownloadAction GET,POST n APP ADMIN
|
||||
/_dr/task/bsaRefresh BsaRefreshAction GET,POST n APP ADMIN
|
||||
/_dr/task/bsaValidate BsaValidateAction GET,POST n APP ADMIN
|
||||
/_dr/task/uploadBsaUnavailableNames UploadBsaUnavailableDomainsAction GET,POST n APP ADMIN
|
||||
SERVICE PATH CLASS METHODS OK MIN USER_POLICY
|
||||
BACKEND /_dr/task/bsaDownload BsaDownloadAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/task/bsaRefresh BsaRefreshAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/task/bsaValidate BsaValidateAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/task/uploadBsaUnavailableNames UploadBsaUnavailableDomainsAction GET,POST n APP ADMIN
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
PATH CLASS METHODS OK MIN USER_POLICY
|
||||
/_dr/epp EppTlsAction POST n APP ADMIN
|
||||
/console-api/domain ConsoleDomainGetAction GET n USER PUBLIC
|
||||
/console-api/domain-list ConsoleDomainListAction GET n USER PUBLIC
|
||||
/console-api/dum-download ConsoleDumDownloadAction GET n USER PUBLIC
|
||||
/console-api/eppPassword ConsoleEppPasswordAction POST n USER PUBLIC
|
||||
/console-api/registrar ConsoleUpdateRegistrarAction POST n USER PUBLIC
|
||||
/console-api/registrars RegistrarsAction GET,POST n USER PUBLIC
|
||||
/console-api/registry-lock ConsoleRegistryLockAction GET,POST n USER PUBLIC
|
||||
/console-api/registry-lock-verify ConsoleRegistryLockVerifyAction GET n USER PUBLIC
|
||||
/console-api/settings/contacts ContactAction GET,POST n USER PUBLIC
|
||||
/console-api/settings/security SecurityAction POST n USER PUBLIC
|
||||
/console-api/settings/whois-fields WhoisRegistrarFieldsAction POST n USER PUBLIC
|
||||
/console-api/userdata ConsoleUserDataAction GET n USER PUBLIC
|
||||
/registrar ConsoleUiAction GET n USER PUBLIC
|
||||
/registrar-create ConsoleRegistrarCreatorAction POST,GET n USER PUBLIC
|
||||
/registrar-ote-setup ConsoleOteSetupAction POST,GET n USER PUBLIC
|
||||
/registrar-ote-status OteStatusAction POST n USER PUBLIC
|
||||
/registrar-settings RegistrarSettingsAction POST n USER PUBLIC
|
||||
/registry-lock-get RegistryLockGetAction GET n USER PUBLIC
|
||||
/registry-lock-post RegistryLockPostAction POST n USER PUBLIC
|
||||
/registry-lock-verify RegistryLockVerifyAction GET n USER PUBLIC
|
||||
SERVICE PATH CLASS METHODS OK MIN USER_POLICY
|
||||
FRONTEND /_dr/epp EppTlsAction POST n APP ADMIN
|
||||
FRONTEND /registrar ConsoleUiAction GET n USER PUBLIC
|
||||
FRONTEND /registrar-create ConsoleRegistrarCreatorAction POST,GET n USER PUBLIC
|
||||
FRONTEND /registrar-ote-setup ConsoleOteSetupAction POST,GET n USER PUBLIC
|
||||
FRONTEND /registrar-ote-status OteStatusAction POST n USER PUBLIC
|
||||
FRONTEND /registrar-settings RegistrarSettingsAction POST n USER PUBLIC
|
||||
FRONTEND /registry-lock-get RegistryLockGetAction GET n USER PUBLIC
|
||||
FRONTEND /registry-lock-post RegistryLockPostAction POST n USER PUBLIC
|
||||
FRONTEND /registry-lock-verify RegistryLockVerifyAction GET n USER PUBLIC
|
||||
CONSOLE /console-api/domain ConsoleDomainGetAction GET n USER PUBLIC
|
||||
CONSOLE /console-api/domain-list ConsoleDomainListAction GET n USER PUBLIC
|
||||
CONSOLE /console-api/dum-download ConsoleDumDownloadAction GET n USER PUBLIC
|
||||
CONSOLE /console-api/eppPassword ConsoleEppPasswordAction POST n USER PUBLIC
|
||||
CONSOLE /console-api/ote ConsoleOteAction GET,POST n USER PUBLIC
|
||||
CONSOLE /console-api/registrar ConsoleUpdateRegistrarAction POST n USER PUBLIC
|
||||
CONSOLE /console-api/registrars RegistrarsAction GET,POST n USER PUBLIC
|
||||
CONSOLE /console-api/registry-lock ConsoleRegistryLockAction GET,POST n USER PUBLIC
|
||||
CONSOLE /console-api/registry-lock-verify ConsoleRegistryLockVerifyAction GET n USER PUBLIC
|
||||
CONSOLE /console-api/settings/contacts ContactAction GET,POST n USER PUBLIC
|
||||
CONSOLE /console-api/settings/security SecurityAction POST n USER PUBLIC
|
||||
CONSOLE /console-api/settings/whois-fields WhoisRegistrarFieldsAction POST n USER PUBLIC
|
||||
CONSOLE /console-api/userdata ConsoleUserDataAction GET n USER PUBLIC
|
||||
@@ -1,13 +1,13 @@
|
||||
PATH CLASS METHODS OK MIN USER_POLICY
|
||||
/_dr/whois WhoisAction POST n APP ADMIN
|
||||
/check CheckApiAction GET n NONE PUBLIC
|
||||
/rdap/autnum/(*) RdapAutnumAction GET,HEAD n NONE PUBLIC
|
||||
/rdap/domain/(*) RdapDomainAction GET,HEAD n NONE PUBLIC
|
||||
/rdap/domains RdapDomainSearchAction GET,HEAD n NONE PUBLIC
|
||||
/rdap/entities RdapEntitySearchAction GET,HEAD n NONE PUBLIC
|
||||
/rdap/entity/(*) RdapEntityAction GET,HEAD n NONE PUBLIC
|
||||
/rdap/help(*) RdapHelpAction GET,HEAD n NONE PUBLIC
|
||||
/rdap/ip/(*) RdapIpAction GET,HEAD n NONE PUBLIC
|
||||
/rdap/nameserver/(*) RdapNameserverAction GET,HEAD n NONE PUBLIC
|
||||
/rdap/nameservers RdapNameserverSearchAction GET,HEAD n NONE PUBLIC
|
||||
/whois/(*) WhoisHttpAction GET n NONE PUBLIC
|
||||
SERVICE PATH CLASS METHODS OK MIN USER_POLICY
|
||||
PUBAPI /_dr/whois WhoisAction POST n APP ADMIN
|
||||
PUBAPI /check CheckApiAction GET n NONE PUBLIC
|
||||
PUBAPI /rdap/autnum/(*) RdapAutnumAction GET,HEAD n NONE PUBLIC
|
||||
PUBAPI /rdap/domain/(*) RdapDomainAction GET,HEAD n NONE PUBLIC
|
||||
PUBAPI /rdap/domains RdapDomainSearchAction GET,HEAD n NONE PUBLIC
|
||||
PUBAPI /rdap/entities RdapEntitySearchAction GET,HEAD n NONE PUBLIC
|
||||
PUBAPI /rdap/entity/(*) RdapEntityAction GET,HEAD n NONE PUBLIC
|
||||
PUBAPI /rdap/help(*) RdapHelpAction GET,HEAD n NONE PUBLIC
|
||||
PUBAPI /rdap/ip/(*) RdapIpAction GET,HEAD n NONE PUBLIC
|
||||
PUBAPI /rdap/nameserver/(*) RdapNameserverAction GET,HEAD n NONE PUBLIC
|
||||
PUBAPI /rdap/nameservers RdapNameserverSearchAction GET,HEAD n NONE PUBLIC
|
||||
PUBAPI /whois/(*) WhoisHttpAction GET n NONE PUBLIC
|
||||
|
||||
@@ -1,88 +1,81 @@
|
||||
PATH CLASS METHODS OK MIN USER_POLICY
|
||||
/_dr/admin/createGroups CreateGroupsAction POST n APP ADMIN
|
||||
/_dr/admin/list/domains ListDomainsAction GET,POST n APP ADMIN
|
||||
/_dr/admin/list/hosts ListHostsAction GET,POST n APP ADMIN
|
||||
/_dr/admin/list/premiumLists ListPremiumListsAction GET,POST n APP ADMIN
|
||||
/_dr/admin/list/registrars ListRegistrarsAction GET,POST n APP ADMIN
|
||||
/_dr/admin/list/reservedLists ListReservedListsAction GET,POST n APP ADMIN
|
||||
/_dr/admin/list/tlds ListTldsAction GET,POST n APP ADMIN
|
||||
/_dr/admin/updateUserGroup UpdateUserGroupAction POST n APP ADMIN
|
||||
/_dr/admin/verifyOte VerifyOteAction POST n APP ADMIN
|
||||
/_dr/cron/fanout TldFanoutAction GET y APP ADMIN
|
||||
/_dr/dnsRefresh RefreshDnsAction GET y APP ADMIN
|
||||
/_dr/epp EppTlsAction POST n APP ADMIN
|
||||
/_dr/epptool EppToolAction POST n APP ADMIN
|
||||
/_dr/loadtest LoadTestAction POST y APP ADMIN
|
||||
/_dr/task/brdaCopy BrdaCopyAction POST y APP ADMIN
|
||||
/_dr/task/bsaDownload BsaDownloadAction GET,POST n APP ADMIN
|
||||
/_dr/task/bsaRefresh BsaRefreshAction GET,POST n APP ADMIN
|
||||
/_dr/task/bsaValidate BsaValidateAction GET,POST n APP ADMIN
|
||||
/_dr/task/copyDetailReports CopyDetailReportsAction POST n APP ADMIN
|
||||
/_dr/task/deleteExpiredDomains DeleteExpiredDomainsAction GET n APP ADMIN
|
||||
/_dr/task/deleteLoadTestData DeleteLoadTestDataAction POST n APP ADMIN
|
||||
/_dr/task/deleteProberData DeleteProberDataAction POST n APP ADMIN
|
||||
/_dr/task/executeCannedScript CannedScriptExecutionAction POST,GET y APP ADMIN
|
||||
/_dr/task/expandBillingRecurrences ExpandBillingRecurrencesAction GET n APP ADMIN
|
||||
/_dr/task/exportDomainLists ExportDomainListsAction POST n APP ADMIN
|
||||
/_dr/task/exportPremiumTerms ExportPremiumTermsAction POST n APP ADMIN
|
||||
/_dr/task/exportReservedTerms ExportReservedTermsAction POST n APP ADMIN
|
||||
/_dr/task/generateInvoices GenerateInvoicesAction POST n APP ADMIN
|
||||
/_dr/task/generateSpec11 GenerateSpec11ReportAction POST n APP ADMIN
|
||||
/_dr/task/generateZoneFiles GenerateZoneFilesAction POST n APP ADMIN
|
||||
/_dr/task/icannReportingStaging IcannReportingStagingAction POST n APP ADMIN
|
||||
/_dr/task/icannReportingUpload IcannReportingUploadAction POST n APP ADMIN
|
||||
/_dr/task/nordnUpload NordnUploadAction POST y APP ADMIN
|
||||
/_dr/task/nordnVerify NordnVerifyAction POST y APP ADMIN
|
||||
/_dr/task/publishDnsUpdates PublishDnsUpdatesAction POST y APP ADMIN
|
||||
/_dr/task/publishInvoices PublishInvoicesAction POST n APP ADMIN
|
||||
/_dr/task/publishSpec11 PublishSpec11ReportAction POST n APP ADMIN
|
||||
/_dr/task/rdeReport RdeReportAction POST n APP ADMIN
|
||||
/_dr/task/rdeStaging RdeStagingAction GET,POST n APP ADMIN
|
||||
/_dr/task/rdeUpload RdeUploadAction POST n APP ADMIN
|
||||
/_dr/task/readDnsRefreshRequests ReadDnsRefreshRequestsAction POST y APP ADMIN
|
||||
/_dr/task/refreshDnsForAllDomains RefreshDnsForAllDomainsAction GET n APP ADMIN
|
||||
/_dr/task/refreshDnsOnHostRename RefreshDnsOnHostRenameAction POST n APP ADMIN
|
||||
/_dr/task/relockDomain RelockDomainAction POST y APP ADMIN
|
||||
/_dr/task/resaveAllEppResourcesPipeline ResaveAllEppResourcesPipelineAction GET n APP ADMIN
|
||||
/_dr/task/resaveEntity ResaveEntityAction POST n APP ADMIN
|
||||
/_dr/task/sendExpiringCertificateNotificationEmail SendExpiringCertificateNotificationEmailAction GET n APP ADMIN
|
||||
/_dr/task/syncGroupMembers SyncGroupMembersAction POST n APP ADMIN
|
||||
/_dr/task/syncRegistrarsSheet SyncRegistrarsSheetAction POST n APP ADMIN
|
||||
/_dr/task/tmchCrl TmchCrlAction POST y APP ADMIN
|
||||
/_dr/task/tmchDnl TmchDnlAction POST y APP ADMIN
|
||||
/_dr/task/tmchSmdrl TmchSmdrlAction POST y APP ADMIN
|
||||
/_dr/task/updateRegistrarRdapBaseUrls UpdateRegistrarRdapBaseUrlsAction GET y APP ADMIN
|
||||
/_dr/task/uploadBsaUnavailableNames UploadBsaUnavailableDomainsAction GET,POST n APP ADMIN
|
||||
/_dr/task/wipeOutContactHistoryPii WipeOutContactHistoryPiiAction GET n APP ADMIN
|
||||
/_dr/whois WhoisAction POST n APP ADMIN
|
||||
/check CheckApiAction GET n NONE PUBLIC
|
||||
/console-api/domain ConsoleDomainGetAction GET n USER PUBLIC
|
||||
/console-api/domain-list ConsoleDomainListAction GET n USER PUBLIC
|
||||
/console-api/dum-download ConsoleDumDownloadAction GET n USER PUBLIC
|
||||
/console-api/eppPassword ConsoleEppPasswordAction POST n USER PUBLIC
|
||||
/console-api/registrar ConsoleUpdateRegistrarAction POST n USER PUBLIC
|
||||
/console-api/registrars RegistrarsAction GET,POST n USER PUBLIC
|
||||
/console-api/registry-lock ConsoleRegistryLockAction GET,POST n USER PUBLIC
|
||||
/console-api/registry-lock-verify ConsoleRegistryLockVerifyAction GET n USER PUBLIC
|
||||
/console-api/settings/contacts ContactAction GET,POST n USER PUBLIC
|
||||
/console-api/settings/security SecurityAction POST n USER PUBLIC
|
||||
/console-api/settings/whois-fields WhoisRegistrarFieldsAction POST n USER PUBLIC
|
||||
/console-api/userdata ConsoleUserDataAction GET n USER PUBLIC
|
||||
/rdap/autnum/(*) RdapAutnumAction GET,HEAD n NONE PUBLIC
|
||||
/rdap/domain/(*) RdapDomainAction GET,HEAD n NONE PUBLIC
|
||||
/rdap/domains RdapDomainSearchAction GET,HEAD n NONE PUBLIC
|
||||
/rdap/entities RdapEntitySearchAction GET,HEAD n NONE PUBLIC
|
||||
/rdap/entity/(*) RdapEntityAction GET,HEAD n NONE PUBLIC
|
||||
/rdap/help(*) RdapHelpAction GET,HEAD n NONE PUBLIC
|
||||
/rdap/ip/(*) RdapIpAction GET,HEAD n NONE PUBLIC
|
||||
/rdap/nameserver/(*) RdapNameserverAction GET,HEAD n NONE PUBLIC
|
||||
/rdap/nameservers RdapNameserverSearchAction GET,HEAD n NONE PUBLIC
|
||||
/registrar ConsoleUiAction GET n USER PUBLIC
|
||||
/registrar-create ConsoleRegistrarCreatorAction POST,GET n USER PUBLIC
|
||||
/registrar-ote-setup ConsoleOteSetupAction POST,GET n USER PUBLIC
|
||||
/registrar-ote-status OteStatusAction POST n USER PUBLIC
|
||||
/registrar-settings RegistrarSettingsAction POST n USER PUBLIC
|
||||
/registry-lock-get RegistryLockGetAction GET n USER PUBLIC
|
||||
/registry-lock-post RegistryLockPostAction POST n USER PUBLIC
|
||||
/registry-lock-verify RegistryLockVerifyAction GET n USER PUBLIC
|
||||
/whois/(*) WhoisHttpAction GET n NONE PUBLIC
|
||||
SERVICE PATH CLASS METHODS OK MIN USER_POLICY
|
||||
FRONTEND /_dr/epp EppTlsAction POST n APP ADMIN
|
||||
BACKEND /_dr/admin/createGroups CreateGroupsAction POST n APP ADMIN
|
||||
BACKEND /_dr/admin/list/domains ListDomainsAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/admin/list/hosts ListHostsAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/admin/list/premiumLists ListPremiumListsAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/admin/list/registrars ListRegistrarsAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/admin/list/reservedLists ListReservedListsAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/admin/list/tlds ListTldsAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/admin/updateUserGroup UpdateUserGroupAction POST n APP ADMIN
|
||||
BACKEND /_dr/admin/verifyOte VerifyOteAction POST n APP ADMIN
|
||||
BACKEND /_dr/cron/fanout TldFanoutAction GET y APP ADMIN
|
||||
BACKEND /_dr/epptool EppToolAction POST n APP ADMIN
|
||||
BACKEND /_dr/loadtest LoadTestAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/brdaCopy BrdaCopyAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/bsaDownload BsaDownloadAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/task/bsaRefresh BsaRefreshAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/task/bsaValidate BsaValidateAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/task/copyDetailReports CopyDetailReportsAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/deleteExpiredDomains DeleteExpiredDomainsAction GET n APP ADMIN
|
||||
BACKEND /_dr/task/deleteLoadTestData DeleteLoadTestDataAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/deleteProberData DeleteProberDataAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/dnsRefresh RefreshDnsAction GET y APP ADMIN
|
||||
BACKEND /_dr/task/executeCannedScript CannedScriptExecutionAction POST,GET y APP ADMIN
|
||||
BACKEND /_dr/task/expandBillingRecurrences ExpandBillingRecurrencesAction GET n APP ADMIN
|
||||
BACKEND /_dr/task/exportDomainLists ExportDomainListsAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/exportPremiumTerms ExportPremiumTermsAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/exportReservedTerms ExportReservedTermsAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/generateInvoices GenerateInvoicesAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/generateSpec11 GenerateSpec11ReportAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/generateZoneFiles GenerateZoneFilesAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/icannReportingStaging IcannReportingStagingAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/icannReportingUpload IcannReportingUploadAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/nordnUpload NordnUploadAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/nordnVerify NordnVerifyAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/publishDnsUpdates PublishDnsUpdatesAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/publishInvoices PublishInvoicesAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/publishSpec11 PublishSpec11ReportAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/rdeReport RdeReportAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/rdeStaging RdeStagingAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/task/rdeUpload RdeUploadAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/readDnsRefreshRequests ReadDnsRefreshRequestsAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/refreshDnsForAllDomains RefreshDnsForAllDomainsAction GET n APP ADMIN
|
||||
BACKEND /_dr/task/refreshDnsOnHostRename RefreshDnsOnHostRenameAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/relockDomain RelockDomainAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/resaveAllEppResourcesPipeline ResaveAllEppResourcesPipelineAction GET n APP ADMIN
|
||||
BACKEND /_dr/task/resaveEntity ResaveEntityAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/sendExpiringCertificateNotificationEmail SendExpiringCertificateNotificationEmailAction GET n APP ADMIN
|
||||
BACKEND /_dr/task/syncGroupMembers SyncGroupMembersAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/syncRegistrarsSheet SyncRegistrarsSheetAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/tmchCrl TmchCrlAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/tmchDnl TmchDnlAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/tmchSmdrl TmchSmdrlAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/updateRegistrarRdapBaseUrls UpdateRegistrarRdapBaseUrlsAction GET y APP ADMIN
|
||||
BACKEND /_dr/task/uploadBsaUnavailableNames UploadBsaUnavailableDomainsAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/task/wipeOutContactHistoryPii WipeOutContactHistoryPiiAction GET n APP ADMIN
|
||||
PUBAPI /_dr/whois WhoisAction POST n APP ADMIN
|
||||
PUBAPI /check CheckApiAction GET n NONE PUBLIC
|
||||
PUBAPI /rdap/autnum/(*) RdapAutnumAction GET,HEAD n NONE PUBLIC
|
||||
PUBAPI /rdap/domain/(*) RdapDomainAction GET,HEAD n NONE PUBLIC
|
||||
PUBAPI /rdap/domains RdapDomainSearchAction GET,HEAD n NONE PUBLIC
|
||||
PUBAPI /rdap/entities RdapEntitySearchAction GET,HEAD n NONE PUBLIC
|
||||
PUBAPI /rdap/entity/(*) RdapEntityAction GET,HEAD n NONE PUBLIC
|
||||
PUBAPI /rdap/help(*) RdapHelpAction GET,HEAD n NONE PUBLIC
|
||||
PUBAPI /rdap/ip/(*) RdapIpAction GET,HEAD n NONE PUBLIC
|
||||
PUBAPI /rdap/nameserver/(*) RdapNameserverAction GET,HEAD n NONE PUBLIC
|
||||
PUBAPI /rdap/nameservers RdapNameserverSearchAction GET,HEAD n NONE PUBLIC
|
||||
PUBAPI /whois/(*) WhoisHttpAction GET n NONE PUBLIC
|
||||
CONSOLE /console-api/domain ConsoleDomainGetAction GET n USER PUBLIC
|
||||
CONSOLE /console-api/domain-list ConsoleDomainListAction GET n USER PUBLIC
|
||||
CONSOLE /console-api/dum-download ConsoleDumDownloadAction GET n USER PUBLIC
|
||||
CONSOLE /console-api/eppPassword ConsoleEppPasswordAction POST n USER PUBLIC
|
||||
CONSOLE /console-api/ote ConsoleOteAction GET,POST n USER PUBLIC
|
||||
CONSOLE /console-api/registrar ConsoleUpdateRegistrarAction POST n USER PUBLIC
|
||||
CONSOLE /console-api/registrars RegistrarsAction GET,POST n USER PUBLIC
|
||||
CONSOLE /console-api/registry-lock ConsoleRegistryLockAction GET,POST n USER PUBLIC
|
||||
CONSOLE /console-api/registry-lock-verify ConsoleRegistryLockVerifyAction GET n USER PUBLIC
|
||||
CONSOLE /console-api/settings/contacts ContactAction GET,POST n USER PUBLIC
|
||||
CONSOLE /console-api/settings/security SecurityAction POST n USER PUBLIC
|
||||
CONSOLE /console-api/settings/whois-fields WhoisRegistrarFieldsAction POST n USER PUBLIC
|
||||
CONSOLE /console-api/userdata ConsoleUserDataAction GET n USER PUBLIC
|
||||
@@ -1,14 +1,14 @@
|
||||
PATH CLASS METHODS OK MIN USER_POLICY
|
||||
/_dr/admin/createGroups CreateGroupsAction POST n APP ADMIN
|
||||
/_dr/admin/list/domains ListDomainsAction GET,POST n APP ADMIN
|
||||
/_dr/admin/list/hosts ListHostsAction GET,POST n APP ADMIN
|
||||
/_dr/admin/list/premiumLists ListPremiumListsAction GET,POST n APP ADMIN
|
||||
/_dr/admin/list/registrars ListRegistrarsAction GET,POST n APP ADMIN
|
||||
/_dr/admin/list/reservedLists ListReservedListsAction GET,POST n APP ADMIN
|
||||
/_dr/admin/list/tlds ListTldsAction GET,POST n APP ADMIN
|
||||
/_dr/admin/updateUserGroup UpdateUserGroupAction POST n APP ADMIN
|
||||
/_dr/admin/verifyOte VerifyOteAction POST n APP ADMIN
|
||||
/_dr/epptool EppToolAction POST n APP ADMIN
|
||||
/_dr/loadtest LoadTestAction POST y APP ADMIN
|
||||
/_dr/task/generateZoneFiles GenerateZoneFilesAction POST n APP ADMIN
|
||||
/_dr/task/refreshDnsForAllDomains RefreshDnsForAllDomainsAction GET n APP ADMIN
|
||||
SERVICE PATH CLASS METHODS OK MIN USER_POLICY
|
||||
BACKEND /_dr/admin/createGroups CreateGroupsAction POST n APP ADMIN
|
||||
BACKEND /_dr/admin/list/domains ListDomainsAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/admin/list/hosts ListHostsAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/admin/list/premiumLists ListPremiumListsAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/admin/list/registrars ListRegistrarsAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/admin/list/reservedLists ListReservedListsAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/admin/list/tlds ListTldsAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/admin/updateUserGroup UpdateUserGroupAction POST n APP ADMIN
|
||||
BACKEND /_dr/admin/verifyOte VerifyOteAction POST n APP ADMIN
|
||||
BACKEND /_dr/epptool EppToolAction POST n APP ADMIN
|
||||
BACKEND /_dr/loadtest LoadTestAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/generateZoneFiles GenerateZoneFilesAction POST n APP ADMIN
|
||||
BACKEND /_dr/task/refreshDnsForAllDomains RefreshDnsForAllDomainsAction GET n APP ADMIN
|
||||
|
||||
@@ -85,7 +85,7 @@ tasks.register('run', JavaExec) {
|
||||
tasks.register('deployNomulus', Exec) {
|
||||
dependsOn('pushNomulusImage', ':proxy:pushProxyImage')
|
||||
configure verifyDeploymentConfig
|
||||
commandLine './deploy-nomulus-for-env.sh', "${rootProject.environment}"
|
||||
commandLine './deploy-nomulus-for-env.sh', "${rootProject.environment}", "${rootProject.baseDomain}"
|
||||
}
|
||||
|
||||
project.build.dependsOn(tasks.named('buildNomulusImage'))
|
||||
|
||||
@@ -17,12 +17,13 @@
|
||||
# kills all running pods to force k8s to create new pods using the just-pushed
|
||||
# manifest.
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: $0 alpha|crash|qa"
|
||||
if [[ $# -ne 2 ]]; then
|
||||
echo "Usage: $0 alpha|crash|qa [base_domain]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
environment=${1}
|
||||
base_domain=${2}
|
||||
project="domain-registry-"${environment}
|
||||
current_context=$(kubectl config current-context)
|
||||
while read line
|
||||
@@ -31,16 +32,25 @@ do
|
||||
echo "Updating cluster ${parts[0]} in location ${parts[1]}..."
|
||||
gcloud container clusters get-credentials "${parts[0]}" \
|
||||
--project "${project}" --location "${parts[1]}"
|
||||
sed s/GCP_PROJECT/"${project}"/g "./kubernetes/nomulus-deployment.yaml" | \
|
||||
sed s/ENVIRONMENT/"${environment}"/g | \
|
||||
kubectl apply -f -
|
||||
kubectl apply -f "./kubernetes/nomulus-service.yaml"
|
||||
for service in frontend backend pubapi console
|
||||
do
|
||||
sed s/GCP_PROJECT/"${project}"/g "./kubernetes/nomulus-${service}.yaml" | \
|
||||
sed s/ENVIRONMENT/"${environment}"/g | \
|
||||
kubectl apply -f -
|
||||
done
|
||||
# Kills all running pods, new pods created will be pulling the new image.
|
||||
kubectl delete pods --all
|
||||
# The multi-cluster gateway is only deployed to one cluster (the one in the US).
|
||||
if [[ "${parts[1]}" == us-* ]]
|
||||
then
|
||||
kubectl apply -f "./kubernetes/nomulus-gateway.yaml"
|
||||
kubectl apply -f "./kubernetes/gateway/nomulus-gateway.yaml"
|
||||
for service in frontend backend pubapi console
|
||||
do
|
||||
sed s/BASE_DOMAIN/"${base_domain}"/g "./kubernetes/gateway/nomulus-route-${service}.yaml" | \
|
||||
kubectl apply -f -
|
||||
sed s/SERVICE/"${service}"/g "./kubernetes/gateway/nomulus-iap-${environment}.yaml" | \
|
||||
kubectl apply -f -
|
||||
done
|
||||
fi
|
||||
done < <(gcloud container clusters list --project "${project}" | grep nomulus)
|
||||
kubectl config use-context "$current_context"
|
||||
|
||||
17
jetty/kubernetes/gateway/nomulus-gateway.yaml
Normal file
17
jetty/kubernetes/gateway/nomulus-gateway.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
apiVersion: gateway.networking.k8s.io/v1beta1
|
||||
kind: Gateway
|
||||
metadata:
|
||||
name: nomulus
|
||||
spec:
|
||||
gatewayClassName: gke-l7-global-external-managed-mc
|
||||
listeners:
|
||||
- name: https
|
||||
protocol: HTTPS
|
||||
port: 443
|
||||
tls:
|
||||
mode: Terminate
|
||||
options:
|
||||
networking.gke.io/pre-shared-certs: nomulus
|
||||
allowedRoutes:
|
||||
kinds:
|
||||
- kind: HTTPRoute
|
||||
47
jetty/kubernetes/gateway/nomulus-route-backend.yaml
Normal file
47
jetty/kubernetes/gateway/nomulus-route-backend.yaml
Normal file
@@ -0,0 +1,47 @@
|
||||
apiVersion: gateway.networking.k8s.io/v1beta1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: backend
|
||||
spec:
|
||||
parentRefs:
|
||||
- kind: Gateway
|
||||
name: nomulus
|
||||
hostnames:
|
||||
- "backend.BASE_DOMAIN"
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /_dr/task
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /_dr/cron
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /_dr/admin
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /_dr/epptool
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /loadtest
|
||||
backendRefs:
|
||||
- group: net.gke.io
|
||||
kind: ServiceImport
|
||||
name: backend
|
||||
port: 80
|
||||
---
|
||||
apiVersion: networking.gke.io/v1
|
||||
kind: HealthCheckPolicy
|
||||
metadata:
|
||||
name: backend
|
||||
spec:
|
||||
default:
|
||||
config:
|
||||
type: HTTP
|
||||
httpHealthCheck:
|
||||
requestPath: /healthz/
|
||||
targetRef:
|
||||
group: net.gke.io
|
||||
kind: ServiceImport
|
||||
name: backend
|
||||
@@ -1,38 +1,31 @@
|
||||
kind: Gateway
|
||||
apiVersion: gateway.networking.k8s.io/v1beta1
|
||||
metadata:
|
||||
name: nomulus
|
||||
spec:
|
||||
gatewayClassName: gke-l7-global-external-managed-mc
|
||||
listeners:
|
||||
- name: http
|
||||
protocol: HTTP
|
||||
port: 80
|
||||
allowedRoutes:
|
||||
kinds:
|
||||
- kind: HTTPRoute
|
||||
---
|
||||
kind: HTTPRoute
|
||||
apiVersion: gateway.networking.k8s.io/v1beta1
|
||||
metadata:
|
||||
name: nomulus
|
||||
labels:
|
||||
app: nomulus
|
||||
name: console
|
||||
spec:
|
||||
parentRefs:
|
||||
- kind: Gateway
|
||||
name: nomulus
|
||||
hostnames:
|
||||
- "console.BASE_DOMAIN"
|
||||
rules:
|
||||
- backendRefs:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /console-api
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /console
|
||||
backendRefs:
|
||||
- group: net.gke.io
|
||||
kind: ServiceImport
|
||||
name: nomulus
|
||||
name: console
|
||||
port: 80
|
||||
---
|
||||
apiVersion: networking.gke.io/v1
|
||||
kind: HealthCheckPolicy
|
||||
metadata:
|
||||
name: nomulus
|
||||
name: console
|
||||
spec:
|
||||
default:
|
||||
config:
|
||||
@@ -42,5 +35,4 @@ spec:
|
||||
targetRef:
|
||||
group: net.gke.io
|
||||
kind: ServiceImport
|
||||
name: nomulus
|
||||
|
||||
name: console
|
||||
35
jetty/kubernetes/gateway/nomulus-route-frontend.yaml
Normal file
35
jetty/kubernetes/gateway/nomulus-route-frontend.yaml
Normal file
@@ -0,0 +1,35 @@
|
||||
apiVersion: gateway.networking.k8s.io/v1beta1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: frontend
|
||||
spec:
|
||||
parentRefs:
|
||||
- kind: Gateway
|
||||
name: nomulus
|
||||
hostnames:
|
||||
- "frontend.BASE_DOMAIN"
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /_dr/epp
|
||||
backendRefs:
|
||||
- group: net.gke.io
|
||||
kind: ServiceImport
|
||||
name: frontend
|
||||
port: 80
|
||||
---
|
||||
apiVersion: networking.gke.io/v1
|
||||
kind: HealthCheckPolicy
|
||||
metadata:
|
||||
name: frontend
|
||||
spec:
|
||||
default:
|
||||
config:
|
||||
type: HTTP
|
||||
httpHealthCheck:
|
||||
requestPath: /healthz/
|
||||
targetRef:
|
||||
group: net.gke.io
|
||||
kind: ServiceImport
|
||||
name: frontend
|
||||
44
jetty/kubernetes/gateway/nomulus-route-pubapi.yaml
Normal file
44
jetty/kubernetes/gateway/nomulus-route-pubapi.yaml
Normal file
@@ -0,0 +1,44 @@
|
||||
apiVersion: gateway.networking.k8s.io/v1beta1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: pubapi
|
||||
spec:
|
||||
parentRefs:
|
||||
- kind: Gateway
|
||||
name: nomulus
|
||||
hostnames:
|
||||
- "pubapi.BASE_DOMAIN"
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /_dr/whois
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /check
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /whois
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /rdap
|
||||
backendRefs:
|
||||
- group: net.gke.io
|
||||
kind: ServiceImport
|
||||
name: pubapi
|
||||
port: 80
|
||||
---
|
||||
apiVersion: networking.gke.io/v1
|
||||
kind: HealthCheckPolicy
|
||||
metadata:
|
||||
name: pubapi
|
||||
spec:
|
||||
default:
|
||||
config:
|
||||
type: HTTP
|
||||
httpHealthCheck:
|
||||
requestPath: /healthz/
|
||||
targetRef:
|
||||
group: net.gke.io
|
||||
kind: ServiceImport
|
||||
name: pubapi
|
||||
60
jetty/kubernetes/nomulus-backend.yaml
Normal file
60
jetty/kubernetes/nomulus-backend.yaml
Normal file
@@ -0,0 +1,60 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: backend
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
service: backend
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
service: backend
|
||||
spec:
|
||||
serviceAccountName: nomulus
|
||||
containers:
|
||||
- name: backend
|
||||
image: gcr.io/GCP_PROJECT/nomulus
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
name: http
|
||||
resources:
|
||||
requests:
|
||||
cpu: "500m"
|
||||
args: [ENVIRONMENT]
|
||||
---
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: backend
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: backend
|
||||
minReplicas: 1
|
||||
maxReplicas: 20
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: 100
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: backend
|
||||
spec:
|
||||
selector:
|
||||
service: backend
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: http
|
||||
name: http
|
||||
---
|
||||
apiVersion: net.gke.io/v1
|
||||
kind: ServiceExport
|
||||
metadata:
|
||||
name: backend
|
||||
60
jetty/kubernetes/nomulus-console.yaml
Normal file
60
jetty/kubernetes/nomulus-console.yaml
Normal file
@@ -0,0 +1,60 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: console
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
service: console
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
service: console
|
||||
spec:
|
||||
serviceAccountName: nomulus
|
||||
containers:
|
||||
- name: console
|
||||
image: gcr.io/GCP_PROJECT/nomulus
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
name: http
|
||||
resources:
|
||||
requests:
|
||||
cpu: "500m"
|
||||
args: [ENVIRONMENT]
|
||||
---
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: console
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: console
|
||||
minReplicas: 1
|
||||
maxReplicas: 20
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: 100
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: console
|
||||
spec:
|
||||
selector:
|
||||
service: console
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: http
|
||||
name: http
|
||||
---
|
||||
apiVersion: net.gke.io/v1
|
||||
kind: ServiceExport
|
||||
metadata:
|
||||
name: console
|
||||
@@ -1,21 +1,19 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nomulus
|
||||
labels:
|
||||
app: nomulus
|
||||
name: frontend
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nomulus
|
||||
service: frontend
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nomulus
|
||||
service: frontend
|
||||
spec:
|
||||
serviceAccountName: nomulus
|
||||
containers:
|
||||
- name: nomulus
|
||||
- name: frontend
|
||||
image: gcr.io/GCP_PROJECT/nomulus
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
@@ -50,14 +48,12 @@ spec:
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: nomulus
|
||||
labels:
|
||||
app: nomulus
|
||||
name: frontend
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: nomulus
|
||||
name: frontend
|
||||
minReplicas: 1
|
||||
maxReplicas: 20
|
||||
metrics:
|
||||
@@ -67,4 +63,26 @@ spec:
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: 100
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: frontend
|
||||
spec:
|
||||
selector:
|
||||
service: frontend
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: http
|
||||
name: http
|
||||
- port: 43
|
||||
targetPort: whois
|
||||
name: whois
|
||||
- port: 700
|
||||
targetPort: epp
|
||||
name: epp
|
||||
---
|
||||
apiVersion: net.gke.io/v1
|
||||
kind: ServiceExport
|
||||
metadata:
|
||||
name: frontend
|
||||
60
jetty/kubernetes/nomulus-pubapi.yaml
Normal file
60
jetty/kubernetes/nomulus-pubapi.yaml
Normal file
@@ -0,0 +1,60 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: pubapi
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
service: pubapi
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
service: pubapi
|
||||
spec:
|
||||
serviceAccountName: nomulus
|
||||
containers:
|
||||
- name: pubapi
|
||||
image: gcr.io/GCP_PROJECT/nomulus
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
name: http
|
||||
resources:
|
||||
requests:
|
||||
cpu: "500m"
|
||||
args: [ENVIRONMENT]
|
||||
---
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: pubapi
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: pubapi
|
||||
minReplicas: 1
|
||||
maxReplicas: 20
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: 100
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: pubapi
|
||||
spec:
|
||||
selector:
|
||||
service: pubapi
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: http
|
||||
name: http
|
||||
---
|
||||
apiVersion: net.gke.io/v1
|
||||
kind: ServiceExport
|
||||
metadata:
|
||||
name: pubapi
|
||||
@@ -1,22 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nomulus
|
||||
spec:
|
||||
selector:
|
||||
app: nomulus
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: http
|
||||
name: http
|
||||
- port: 43
|
||||
targetPort: whois
|
||||
name: whois
|
||||
- port: 700
|
||||
targetPort: epp
|
||||
name: epp
|
||||
---
|
||||
kind: ServiceExport
|
||||
apiVersion: net.gke.io/v1
|
||||
metadata:
|
||||
name: nomulus
|
||||
@@ -25,3 +25,9 @@ rootProject.ext.projects = ['production': 'your-production-project',
|
||||
// The project to host your development/deployment infrastructure. It hosts
|
||||
// things like release artifacts, CI/CD system, etc.
|
||||
rootProject.ext.devProject = 'your-dev-project'
|
||||
|
||||
rootProject.ext.baseDomains = ['production' : 'registry-production.test',
|
||||
'sandbox' : 'registry-sandbox.test',
|
||||
'alpha' : 'registry-alpha.test',
|
||||
'crash' : 'registry-crash.test',
|
||||
'qa' : 'registry-qa.test']
|
||||
|
||||
Reference in New Issue
Block a user